diff --git a/config/functions b/config/functions
index 91636f7847..3fc07d2ee1 100644
--- a/config/functions
+++ b/config/functions
@@ -344,6 +344,25 @@ done
-i "$addon_xml"
}
+install_driver_addon_files() {
+ if [ "$#" -eq 0 ] ; then
+ printf "$(print_color CLR_ERROR "no module search path defined")\n"
+ exit 1
+ fi
+
+ PKG_MODULE_DIR="$INSTALL/$(get_full_module_dir $PKG_ADDON_ID)/updates/$PKG_ADDON_ID"
+ PKG_ADDON_DIR="$INSTALL/usr/share/$MEDIACENTER/addons/$PKG_ADDON_ID"
+
+ mkdir -p $PKG_MODULE_DIR
+ find $@ -name \*.ko -exec cp {} $PKG_MODULE_DIR \;
+
+ find $PKG_MODULE_DIR -name \*.ko -exec $STRIP --strip-debug {} \;
+
+ mkdir -p $PKG_ADDON_DIR
+ cp $PKG_DIR/changelog.txt $PKG_ADDON_DIR
+ install_addon_files "$PKG_ADDON_DIR"
+}
+
install_addon_files() {
install_addon_source "$1"
install_addon_images "$1"
@@ -634,6 +653,12 @@ show_config() {
config_message="$config_message\n - Include driver:\t\t\t $config_driver"
done
+ if [ "$DRIVER_ADDONS_SUPPORT" = "yes" ]; then
+ for config_driver_addons in $DRIVER_ADDONS; do
+ config_message="$config_message\n - Include driver add-ons:\t\t $config_driver_addons"
+ done
+ fi
+
for config_firmware in $FIRMWARE; do
config_message="$config_message\n - Include firmware:\t\t\t $config_firmware"
done
diff --git a/config/path b/config/path
index ed96f45eb9..8a0ddc822b 100644
--- a/config/path
+++ b/config/path
@@ -119,7 +119,7 @@ unset LD_LIBRARY_PATH
if [ "$PKG_IS_ADDON" = "yes" ] ; then
[ -z $PKG_SECTION ] && PKG_ADDON_ID="$PKG_NAME" || PKG_ADDON_ID="${PKG_SECTION//\//.}.$PKG_NAME"
- PKG_NEED_UNPACK="${PKG_NEED_UNPACK} $(get_pkg_directory $MEDIACENTER)"
+ [ "$PKG_ADDON_IS_STANDALONE" != "yes" ] && PKG_NEED_UNPACK="${PKG_NEED_UNPACK} $(get_pkg_directory $MEDIACENTER)"
fi
# Automatically set PKG_SOURCE_NAME unless it is already defined.
diff --git a/packages/addons/script/driverselect/package.mk b/packages/addons/script/driverselect/package.mk
new file mode 100644
index 0000000000..601aaee471
--- /dev/null
+++ b/packages/addons/script/driverselect/package.mk
@@ -0,0 +1,50 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2017-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
+
+PKG_NAME="driverselect"
+PKG_VERSION="2b79180"
+PKG_SHA256="ed1e9defa185b46d4400794681f21f2bf1ddf8ccdfdb20e49ddde3edccdd6b7f"
+PKG_REV="100"
+PKG_ARCH="any"
+PKG_LICENSE="OSS"
+PKG_SITE="https://libreelec.tv"
+PKG_URL="https://github.com/b-jesch/script.program.driverselect/archive/$PKG_VERSION.tar.gz"
+PKG_SOURCE_DIR="${PKG_SECTION}.${PKG_NAME}-${PKG_VERSION}*"
+PKG_DEPENDS_TARGET="toolchain"
+PKG_SECTION="script.program"
+PKG_SHORTDESC="script.program.driverselect"
+PKG_LONGDESC="script.program.driverselect"
+PKG_TOOLCHAIN="manual"
+
+PKG_IS_ADDON="yes"
+PKG_ADDON_NAME="Driver Select"
+PKG_ADDON_TYPE="xbmc.python.script"
+
+unpack() {
+ mkdir -p $PKG_BUILD/addon
+ tar --strip-components=1 -xf $SOURCES/$PKG_NAME/$PKG_NAME-$PKG_VERSION.tar.gz -C $PKG_BUILD/addon
+}
+
+make_target() {
+ :
+}
+
+makeinstall_target() {
+ mkdir -p $INSTALL/usr/share/kodi/addons/${PKG_SECTION}.${PKG_NAME}
+ cp -rP $PKG_BUILD/addon/* $INSTALL/usr/share/kodi/addons/${PKG_SECTION}.${PKG_NAME}
+}
diff --git a/packages/linux-driver-addons/dvb/crazycat/changelog.txt b/packages/linux-driver-addons/dvb/crazycat/changelog.txt
new file mode 100755
index 0000000000..32d81ca428
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/crazycat/changelog.txt
@@ -0,0 +1,2 @@
+100
+- Initial add-on
diff --git a/packages/linux-drivers/media_build/config/generic.config b/packages/linux-driver-addons/dvb/crazycat/config/generic.config
similarity index 94%
rename from packages/linux-drivers/media_build/config/generic.config
rename to packages/linux-driver-addons/dvb/crazycat/config/generic.config
index 36fb96b292..cb8f5ae5ca 100644
--- a/packages/linux-drivers/media_build/config/generic.config
+++ b/packages/linux-driver-addons/dvb/crazycat/config/generic.config
@@ -2,150 +2,191 @@
# Automatically generated file; DO NOT EDIT.
# V4L/DVB menu
#
-# CONFIG_SOC_EXYNOS4212 is not set
-# CONFIG_PWM_OMAP_DMTIMER is not set
-# CONFIG_ARCH_OMAP3 is not set
-# CONFIG_BROKEN is not set
-# CONFIG_ARM_DMA_USE_IOMMU is not set
-CONFIG_HDMI=y
-CONFIG_LEDS_CLASS_FLASH=y
-CONFIG_PCI_MSI=y
-# CONFIG_MTK_IOMMU_V1 is not set
-# CONFIG_RPMSG is not set
-# CONFIG_PLAT_S3C24XX is not set
-# CONFIG_FB_VIA is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_I2C_GPIO is not set
-CONFIG_I2C=y
+# CONFIG_ARCH_STI is not set
+# CONFIG_TI_ST is not set
CONFIG_HAVE_CLK=y
-# CONFIG_REGULATOR is not set
-CONFIG_PM=y
-# CONFIG_ARCH_MEDIATEK is not set
-# CONFIG_ISA is not set
-CONFIG_DEBUG_FS=y
-CONFIG_MODULES=y
-# CONFIG_SPI is not set
+CONFIG_I2C_MUX=m
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_METAG is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_MXC is not set
# CONFIG_MFD_WL1273_CORE is not set
-CONFIG_SND_PCM=y
-CONFIG_MMU=y
-CONFIG_MFD_CORE=y
-CONFIG_MMC=y
-CONFIG_USB=y
-CONFIG_SYSFS=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS_CLASS=y
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_FONT_SUPPORT=y
-CONFIG_RATIONAL=y
+CONFIG_TTY=y
+CONFIG_ISA_DMA_API=y
+CONFIG_USB_ACM=m
+# CONFIG_SPARC32 is not set
+# CONFIG_ARCH_MMP is not set
+CONFIG_PCI_MSI=y
+# CONFIG_MFD_TIMBERDALE is not set
+CONFIG_FB=y
+CONFIG_HAS_DMA=y
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_IMX_IPUV3_CORE is not set
+CONFIG_NET=y
+# CONFIG_PXA27x is not set
+# CONFIG_ARCH_DAVINCI_DM365 is not set
+# CONFIG_OF is not set
+# CONFIG_SRAM is not set
+# CONFIG_SND_SOC_SI476X is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_QCOM_MDT_LOADER is not set
+# CONFIG_ARCH_RENESAS is not set
+# CONFIG_SPARC64 is not set
+# CONFIG_ARCH_S3C64XX is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FB_OMAP2 is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARCH_S5PV210 is not set
CONFIG_CRC32=y
+CONFIG_SND=y
+CONFIG_RFKILL=m
+# CONFIG_M32R is not set
+CONFIG_PINCTRL=y
+# CONFIG_SG_SPLIT is not set
+CONFIG_MODULES=y
+CONFIG_REGMAP_I2C=y
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_ARCH_ZX is not set
+# CONFIG_MFD_SI476X_CORE is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_FB_VIA is not set
+CONFIG_REGMAP=y
+CONFIG_PCI=y
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_QCOM_SCM is not set
+# CONFIG_PLAT_S5P is not set
CONFIG_SERIO=y
# CONFIG_ARCH_SUNXI is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_PLAT_S5P is not set
-# CONFIG_OMAP_DM_TIMER is not set
-# CONFIG_MFD_TIMBERDALE is not set
-# CONFIG_SND_ISA is not set
-CONFIG_ISA_DMA_API=y
-CONFIG_NEW_LEDS=y
-CONFIG_PCI=y
-# CONFIG_ARCH_OMAP2PLUS is not set
-# CONFIG_VIDEO_V4L1 is not set
-CONFIG_FW_LOADER=y
-CONFIG_DMA_ENGINE=y
-# CONFIG_GENERIC_PHY is not set
-CONFIG_HAS_IOMEM=y
-CONFIG_NET=y
-# CONFIG_ARCH_EXYNOS is not set
-# CONFIG_SOC_AM43XX is not set
-CONFIG_INET=y
-# CONFIG_SPARC32 is not set
-# CONFIG_TI_ST is not set
-# CONFIG_STA2X11 is not set
-# CONFIG_MTD is not set
-CONFIG_USB_ACM=m
-# CONFIG_ARCH_STM32 is not set
-CONFIG_SND=y
-CONFIG_PINCTRL=y
-CONFIG_PNP=y
-# CONFIG_SRAM is not set
-# CONFIG_SG_SPLIT is not set
-# CONFIG_SONY_LAPTOP is not set
-# CONFIG_ARCH_S5PV210 is not set
-CONFIG_COMMON_CLK=y
-# CONFIG_SOC_IMX27 is not set
-CONFIG_INPUT=y
-# CONFIG_OF is not set
-CONFIG_FONT_8x16=y
-# CONFIG_SOC_EXYNOS5250 is not set
-CONFIG_ACPI=y
-# CONFIG_ARCH_MMP is not set
-CONFIG_FIREWIRE=m
-# CONFIG_PLAT_M32700UT is not set
-CONFIG_DMA_SHARED_BUFFER=y
-# CONFIG_PPC_MPC512x is not set
-CONFIG_X86=y
-# CONFIG_SND_MIRO is not set
-# CONFIG_OMAP_IOMMU is not set
-# CONFIG_ARCH_MULTIPLATFORM is not set
-CONFIG_VIRT_TO_BUS=y
-# CONFIG_ARCH_S3C64XX is not set
-# CONFIG_ARCH_SHMOBILE is not set
-# CONFIG_PXA27x is not set
-# CONFIG_MFD_SI476X_CORE is not set
-# CONFIG_ARM64 is not set
-CONFIG_GPIOLIB=y
-# CONFIG_FB_OMAP2 is not set
# CONFIG_GENERIC_ALLOCATOR is not set
-# CONFIG_OMAP2_VRFB is not set
-CONFIG_BITREVERSE=y
-# CONFIG_BLACKFIN is not set
-# CONFIG_REGMAP_MMIO is not set
-CONFIG_RFKILL=m
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_TTY=y
-# CONFIG_SPI_MASTER is not set
-CONFIG_LEDS_CLASS=y
-# CONFIG_MTK_IOMMU is not set
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_METAG is not set
-CONFIG_REGMAP=y
-# CONFIG_ARCH_MESON is not set
-# CONFIG_M32R is not set
-CONFIG_SND_SOC=y
-# CONFIG_ARCH_OMAP4 is not set
-CONFIG_HAS_DMA=y
-# CONFIG_MFD_SYSCON is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_ARCH_AT91 is not set
-# CONFIG_SPARC64 is not set
-# CONFIG_ARCH_RENESAS is not set
+# CONFIG_ISA is not set
+# CONFIG_PWM is not set
+CONFIG_SYSFS=y
+# CONFIG_BROKEN is not set
+CONFIG_MMC=y
+# CONFIG_MTK_IOMMU_V1 is not set
+# CONFIG_ARCH_TANGO is not set
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_GPIOLIB=y
+# CONFIG_ARM64 is not set
+# CONFIG_ARM_DMA_USE_IOMMU is not set
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_OMAP_DM_TIMER is not set
+# CONFIG_ARCH_EXYNOS is not set
# CONFIG_ALPHA is not set
+CONFIG_LEDS_CLASS_FLASH=y
CONFIG_FB_CFB_COPYAREA=y
-# CONFIG_ARCH_DAVINCI is not set
-# CONFIG_ARCH_MXC is not set
-CONFIG_FB=y
-# CONFIG_ARCH_DAVINCI_DM365 is not set
-# CONFIG_SOC_EXYNOS4412 is not set
-# CONFIG_ARCH_STI is not set
-CONFIG_I2C_MUX=m
-# CONFIG_SND_SOC_SI476X is not set
-CONFIG_REGMAP_I2C=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_FIREWIRE=m
+CONFIG_MFD_CORE=y
+CONFIG_PM=y
+CONFIG_DMA_ENGINE=y
+CONFIG_SND_PCM=y
+# CONFIG_PLAT_S3C24XX is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SPI is not set
+CONFIG_FW_LOADER=y
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_IOMMU_DMA is not set
+CONFIG_USB=y
+CONFIG_PNP=y
+# CONFIG_MTD is not set
CONFIG_I2C_ALGOBIT=y
-# CONFIG_ARCH_OMAP2 is not set
-CONFIG_SERIO_SERPORT=y
+CONFIG_BITREVERSE=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_I2C=y
# CONFIG_MIPS is not set
-CONFIG_EFI=y
-# CONFIG_SOC_DRA7XX is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_STA2X11 is not set
+# CONFIG_PWM_OMAP_DMTIMER is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_BLACKFIN is not set
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MULTIPLEXER is not set
+CONFIG_COMMON_CLK=y
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_OMAP4 is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_STM32 is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_INET=y
+# CONFIG_SOC_IMX27 is not set
+CONFIG_X86=y
+# CONFIG_SOC_EXYNOS4212 is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_OMAP2_VRFB is not set
+CONFIG_INPUT=y
+# CONFIG_RPMSG is not set
+# CONFIG_MTK_IOMMU is not set
+CONFIG_SND_SOC=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_OMAP_IOMMU is not set
+# CONFIG_ARCH_OMAP2PLUS is not set
+CONFIG_MMU=y
+# CONFIG_SOC_EXYNOS5250 is not set
+# CONFIG_REGMAP_MMIO is not set
+CONFIG_RATIONAL=y
+# CONFIG_SND_ISA is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HDMI=y
+# CONFIG_SOC_EXYNOS4412 is not set
+# CONFIG_ARCH_AT91 is not set
# CONFIG_VIDEO_KERNEL_VERSION is not set
+CONFIG_RC_CORE=m
+CONFIG_RC_MAP=m
+CONFIG_RC_DECODERS=y
+CONFIG_LIRC=m
+CONFIG_IR_LIRC_CODEC=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_ENE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_ITE_CIR=m
+CONFIG_IR_FINTEK=m
+CONFIG_IR_NUVOTON=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_WINBOND_CIR=m
+CONFIG_IR_IGORPLUGUSB=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_SERIAL=m
+CONFIG_IR_SERIAL_TRANSMITTER=y
+# CONFIG_IR_SIR is not set
CONFIG_MEDIA_SUPPORT=m
#
# Multimedia core support
#
-CONFIG_MEDIA_CAMERA_SUPPORT=y
+# CONFIG_MEDIA_CAMERA_SUPPORT is not set
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
# CONFIG_MEDIA_RADIO_SUPPORT is not set
# CONFIG_MEDIA_SDR_SUPPORT is not set
-CONFIG_MEDIA_RC_SUPPORT=y
# CONFIG_MEDIA_CEC_SUPPORT is not set
# CONFIG_MEDIA_CONTROLLER is not set
CONFIG_VIDEO_DEV=m
@@ -173,54 +214,8 @@ CONFIG_DVB_DYNAMIC_MINORS=y
#
# Media drivers
#
-CONFIG_RC_CORE=m
-CONFIG_RC_MAP=m
-CONFIG_RC_DECODERS=y
-CONFIG_LIRC=m
-CONFIG_IR_LIRC_CODEC=m
-CONFIG_IR_NEC_DECODER=m
-CONFIG_IR_RC5_DECODER=m
-CONFIG_IR_RC6_DECODER=m
-CONFIG_IR_JVC_DECODER=m
-CONFIG_IR_SONY_DECODER=m
-CONFIG_IR_SANYO_DECODER=m
-CONFIG_IR_SHARP_DECODER=m
-CONFIG_IR_MCE_KBD_DECODER=m
-CONFIG_IR_XMP_DECODER=m
-CONFIG_RC_DEVICES=y
-CONFIG_RC_ATI_REMOTE=m
-CONFIG_IR_ENE=m
-CONFIG_IR_HIX5HD2=m
-CONFIG_IR_IMON=m
-CONFIG_IR_MCEUSB=m
-CONFIG_IR_ITE_CIR=m
-CONFIG_IR_FINTEK=m
-CONFIG_IR_NUVOTON=m
-CONFIG_IR_REDRAT3=m
-CONFIG_IR_STREAMZAP=m
-CONFIG_IR_WINBOND_CIR=m
-CONFIG_IR_IGORPLUGUSB=m
-CONFIG_IR_IGUANA=m
-CONFIG_IR_TTUSBIR=m
-CONFIG_RC_LOOPBACK=m
-CONFIG_IR_GPIO_CIR=m
-CONFIG_IR_SERIAL=m
-CONFIG_IR_SERIAL_TRANSMITTER=y
-# CONFIG_IR_SIR is not set
CONFIG_MEDIA_USB_SUPPORT=y
-#
-# Webcam devices
-#
-# CONFIG_USB_VIDEO_CLASS is not set
-# CONFIG_USB_GSPCA is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_VIDEO_CPIA2 is not set
-# CONFIG_USB_ZR364XX is not set
-# CONFIG_USB_STKWEBCAM is not set
-# CONFIG_USB_S2255 is not set
-# CONFIG_VIDEO_USBTV is not set
-
#
# Analog TV USB devices
#
@@ -295,6 +290,7 @@ CONFIG_DVB_USB_TBS5881=m
CONFIG_DVB_USB_TBS5520=m
CONFIG_DVB_USB_TBS5927=m
CONFIG_DVB_USB_TBS5520SE=m
+CONFIG_DVB_USB_TBS5580=m
CONFIG_DVB_USB_CYCITV=m
CONFIG_DVB_USB_V2=m
CONFIG_DVB_USB_AF9015=m
@@ -327,15 +323,6 @@ CONFIG_VIDEO_EM28XX_DVB=m
CONFIG_VIDEO_EM28XX_RC=m
CONFIG_MEDIA_PCI_SUPPORT=y
-#
-# Media capture support
-#
-# CONFIG_VIDEO_SOLO6X10 is not set
-# CONFIG_VIDEO_TW5864 is not set
-# CONFIG_VIDEO_TW68 is not set
-# CONFIG_VIDEO_TW686X is not set
-# CONFIG_VIDEO_ZORAN is not set
-
#
# Media capture/analog TV support
#
@@ -394,11 +381,9 @@ CONFIG_DVB_MANTIS=m
CONFIG_DVB_HOPPER=m
CONFIG_DVB_NGENE=m
CONFIG_DVB_DDBRIDGE=m
+# CONFIG_DVB_DDBRIDGE_MSIENABLE is not set
CONFIG_DVB_SMIPCIE=m
CONFIG_DVB_TBSECP3=m
-# CONFIG_V4L_PLATFORM_DRIVERS is not set
-# CONFIG_V4L_MEM2MEM_DRIVERS is not set
-# CONFIG_V4L_TEST_DRIVERS is not set
# CONFIG_DVB_PLATFORM_DRIVERS is not set
#
@@ -467,9 +452,6 @@ CONFIG_VIDEO_CX25840=m
#
# Camera sensor devices
#
-CONFIG_VIDEO_OV2640=m
-CONFIG_VIDEO_OV7640=m
-CONFIG_VIDEO_MT9V011=m
#
# Flash devices
@@ -484,6 +466,10 @@ CONFIG_VIDEO_MT9V011=m
#
CONFIG_VIDEO_SAA6752HS=m
+#
+# SDR tuner chips
+#
+
#
# Miscellaneous helper chips
#
@@ -493,6 +479,7 @@ CONFIG_VIDEO_SAA6752HS=m
#
CONFIG_MEDIA_TUNER=m
CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA18250=m
CONFIG_MEDIA_TUNER_TDA8290=m
CONFIG_MEDIA_TUNER_TDA827X=m
CONFIG_MEDIA_TUNER_TDA18271=m
@@ -534,7 +521,10 @@ CONFIG_MEDIA_TUNER_R848=m
CONFIG_DVB_STB0899=m
CONFIG_DVB_STB6100=m
CONFIG_DVB_STV090x=m
+CONFIG_DVB_STV0910=m
CONFIG_DVB_STV6110x=m
+CONFIG_DVB_STV6111=m
+CONFIG_DVB_MXL5XX=m
CONFIG_DVB_M88DS3103=m
#
@@ -598,6 +588,7 @@ CONFIG_DVB_AF9013=m
CONFIG_DVB_EC100=m
CONFIG_DVB_STV0367=m
CONFIG_DVB_CXD2820R=m
+CONFIG_DVB_CXD2841ER=m
CONFIG_DVB_RTL2830=m
CONFIG_DVB_RTL2832=m
CONFIG_DVB_SI2168=m
@@ -652,6 +643,7 @@ CONFIG_DVB_TUNER_DIB0090=m
# SEC control devices for DVB-S
#
CONFIG_DVB_DRX39XYJ=m
+CONFIG_DVB_LNBH25=m
CONFIG_DVB_LNBP21=m
CONFIG_DVB_LNBP22=m
CONFIG_DVB_ISL6405=m
@@ -668,8 +660,8 @@ CONFIG_DVB_M88RS2000=m
CONFIG_DVB_AF9033=m
CONFIG_DVB_TAS2101=m
CONFIG_DVB_AVL6882=m
-CONFIG_DVB_STV0910=m
-CONFIG_DVB_MXL5XX=m
+CONFIG_DVB_STV091X=m
+CONFIG_DVB_MXL58X=m
CONFIG_DVB_SI2183=m
#
diff --git a/packages/linux-drivers/media_build/config/usb.config b/packages/linux-driver-addons/dvb/crazycat/config/usb.config
similarity index 94%
rename from packages/linux-drivers/media_build/config/usb.config
rename to packages/linux-driver-addons/dvb/crazycat/config/usb.config
index eba2a84c3b..0b85d855d0 100644
--- a/packages/linux-drivers/media_build/config/usb.config
+++ b/packages/linux-driver-addons/dvb/crazycat/config/usb.config
@@ -2,150 +2,191 @@
# Automatically generated file; DO NOT EDIT.
# V4L/DVB menu
#
-# CONFIG_SOC_EXYNOS4212 is not set
-# CONFIG_PWM_OMAP_DMTIMER is not set
-# CONFIG_ARCH_OMAP3 is not set
-# CONFIG_BROKEN is not set
-# CONFIG_ARM_DMA_USE_IOMMU is not set
-CONFIG_HDMI=y
-CONFIG_LEDS_CLASS_FLASH=y
-CONFIG_PCI_MSI=y
-# CONFIG_MTK_IOMMU_V1 is not set
-# CONFIG_RPMSG is not set
-# CONFIG_PLAT_S3C24XX is not set
-# CONFIG_FB_VIA is not set
-# CONFIG_SND_FM801 is not set
-# CONFIG_I2C_GPIO is not set
-CONFIG_I2C=y
+# CONFIG_ARCH_STI is not set
+# CONFIG_TI_ST is not set
CONFIG_HAVE_CLK=y
-# CONFIG_REGULATOR is not set
-CONFIG_PM=y
-# CONFIG_ARCH_MEDIATEK is not set
-# CONFIG_ISA is not set
-CONFIG_DEBUG_FS=y
-CONFIG_MODULES=y
-# CONFIG_SPI is not set
+CONFIG_I2C_MUX=m
+# CONFIG_PLAT_M32700UT is not set
+# CONFIG_METAG is not set
+# CONFIG_ARCH_OMAP3 is not set
+# CONFIG_ARCH_MXC is not set
# CONFIG_MFD_WL1273_CORE is not set
-CONFIG_SND_PCM=y
-CONFIG_MMU=y
-CONFIG_MFD_CORE=y
-CONFIG_MMC=y
-CONFIG_USB=y
-CONFIG_SYSFS=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_LEDS_CLASS=y
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_FONT_SUPPORT=y
-CONFIG_RATIONAL=y
+CONFIG_TTY=y
+CONFIG_ISA_DMA_API=y
+CONFIG_USB_ACM=m
+# CONFIG_SPARC32 is not set
+# CONFIG_ARCH_MMP is not set
+CONFIG_PCI_MSI=y
+# CONFIG_MFD_TIMBERDALE is not set
+CONFIG_FB=y
+CONFIG_HAS_DMA=y
+# CONFIG_SOC_DRA7XX is not set
+# CONFIG_IMX_IPUV3_CORE is not set
+CONFIG_NET=y
+# CONFIG_PXA27x is not set
+# CONFIG_ARCH_DAVINCI_DM365 is not set
+# CONFIG_OF is not set
+# CONFIG_SRAM is not set
+# CONFIG_SND_SOC_SI476X is not set
+# CONFIG_SONY_LAPTOP is not set
+# CONFIG_QCOM_MDT_LOADER is not set
+# CONFIG_ARCH_RENESAS is not set
+# CONFIG_SPARC64 is not set
+# CONFIG_ARCH_S3C64XX is not set
+CONFIG_FONT_8x16=y
+# CONFIG_FB_OMAP2 is not set
+# CONFIG_SPI_MASTER is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_ARCH_S5PV210 is not set
CONFIG_CRC32=y
+CONFIG_SND=y
+CONFIG_RFKILL=m
+# CONFIG_M32R is not set
+CONFIG_PINCTRL=y
+# CONFIG_SG_SPLIT is not set
+CONFIG_MODULES=y
+CONFIG_REGMAP_I2C=y
+# CONFIG_GENERIC_PHY is not set
+# CONFIG_ARCH_ZX is not set
+# CONFIG_MFD_SI476X_CORE is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_FB_VIA is not set
+CONFIG_REGMAP=y
+CONFIG_PCI=y
+# CONFIG_ARCH_MULTIPLATFORM is not set
+# CONFIG_SOC_AM43XX is not set
+# CONFIG_QCOM_SCM is not set
+# CONFIG_PLAT_S5P is not set
CONFIG_SERIO=y
# CONFIG_ARCH_SUNXI is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_PLAT_S5P is not set
-# CONFIG_OMAP_DM_TIMER is not set
-# CONFIG_MFD_TIMBERDALE is not set
-# CONFIG_SND_ISA is not set
-CONFIG_ISA_DMA_API=y
-CONFIG_NEW_LEDS=y
-CONFIG_PCI=y
-# CONFIG_ARCH_OMAP2PLUS is not set
-# CONFIG_VIDEO_V4L1 is not set
-CONFIG_FW_LOADER=y
-CONFIG_DMA_ENGINE=y
-# CONFIG_GENERIC_PHY is not set
-CONFIG_HAS_IOMEM=y
-CONFIG_NET=y
-# CONFIG_ARCH_EXYNOS is not set
-# CONFIG_SOC_AM43XX is not set
-CONFIG_INET=y
-# CONFIG_SPARC32 is not set
-# CONFIG_TI_ST is not set
-# CONFIG_STA2X11 is not set
-# CONFIG_MTD is not set
-CONFIG_USB_ACM=m
-# CONFIG_ARCH_STM32 is not set
-CONFIG_SND=y
-CONFIG_PINCTRL=y
-CONFIG_PNP=y
-# CONFIG_SRAM is not set
-# CONFIG_SG_SPLIT is not set
-# CONFIG_SONY_LAPTOP is not set
-# CONFIG_ARCH_S5PV210 is not set
-CONFIG_COMMON_CLK=y
-# CONFIG_SOC_IMX27 is not set
-CONFIG_INPUT=y
-# CONFIG_OF is not set
-CONFIG_FONT_8x16=y
-# CONFIG_SOC_EXYNOS5250 is not set
-CONFIG_ACPI=y
-# CONFIG_ARCH_MMP is not set
-CONFIG_FIREWIRE=m
-# CONFIG_PLAT_M32700UT is not set
-CONFIG_DMA_SHARED_BUFFER=y
-# CONFIG_PPC_MPC512x is not set
-CONFIG_X86=y
-# CONFIG_SND_MIRO is not set
-# CONFIG_OMAP_IOMMU is not set
-# CONFIG_ARCH_MULTIPLATFORM is not set
-CONFIG_VIRT_TO_BUS=y
-# CONFIG_ARCH_S3C64XX is not set
-# CONFIG_ARCH_SHMOBILE is not set
-# CONFIG_PXA27x is not set
-# CONFIG_MFD_SI476X_CORE is not set
-# CONFIG_ARM64 is not set
-CONFIG_GPIOLIB=y
-# CONFIG_FB_OMAP2 is not set
# CONFIG_GENERIC_ALLOCATOR is not set
-# CONFIG_OMAP2_VRFB is not set
-CONFIG_BITREVERSE=y
-# CONFIG_BLACKFIN is not set
-# CONFIG_REGMAP_MMIO is not set
-CONFIG_RFKILL=m
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_TTY=y
-# CONFIG_SPI_MASTER is not set
-CONFIG_LEDS_CLASS=y
-# CONFIG_MTK_IOMMU is not set
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_METAG is not set
-CONFIG_REGMAP=y
-# CONFIG_ARCH_MESON is not set
-# CONFIG_M32R is not set
-CONFIG_SND_SOC=y
-# CONFIG_ARCH_OMAP4 is not set
-CONFIG_HAS_DMA=y
-# CONFIG_MFD_SYSCON is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_ARCH_AT91 is not set
-# CONFIG_SPARC64 is not set
-# CONFIG_ARCH_RENESAS is not set
+# CONFIG_ISA is not set
+# CONFIG_PWM is not set
+CONFIG_SYSFS=y
+# CONFIG_BROKEN is not set
+CONFIG_MMC=y
+# CONFIG_MTK_IOMMU_V1 is not set
+# CONFIG_ARCH_TANGO is not set
+CONFIG_DMA_SHARED_BUFFER=y
+CONFIG_GPIOLIB=y
+# CONFIG_ARM64 is not set
+# CONFIG_ARM_DMA_USE_IOMMU is not set
+# CONFIG_PPC_MPC512x is not set
+# CONFIG_OMAP_DM_TIMER is not set
+# CONFIG_ARCH_EXYNOS is not set
# CONFIG_ALPHA is not set
+CONFIG_LEDS_CLASS_FLASH=y
CONFIG_FB_CFB_COPYAREA=y
-# CONFIG_ARCH_DAVINCI is not set
-# CONFIG_ARCH_MXC is not set
-CONFIG_FB=y
-# CONFIG_ARCH_DAVINCI_DM365 is not set
-# CONFIG_SOC_EXYNOS4412 is not set
-# CONFIG_ARCH_STI is not set
-CONFIG_I2C_MUX=m
-# CONFIG_SND_SOC_SI476X is not set
-CONFIG_REGMAP_I2C=y
+CONFIG_INPUT_EVDEV=y
+CONFIG_FIREWIRE=m
+CONFIG_MFD_CORE=y
+CONFIG_PM=y
+CONFIG_DMA_ENGINE=y
+CONFIG_SND_PCM=y
+# CONFIG_PLAT_S3C24XX is not set
+# CONFIG_SND_MIRO is not set
+# CONFIG_SPI is not set
+CONFIG_FW_LOADER=y
+# CONFIG_MFD_SYSCON is not set
+# CONFIG_I2C_GPIO is not set
+# CONFIG_IOMMU_DMA is not set
+CONFIG_USB=y
+CONFIG_PNP=y
+# CONFIG_MTD is not set
CONFIG_I2C_ALGOBIT=y
-# CONFIG_ARCH_OMAP2 is not set
-CONFIG_SERIO_SERPORT=y
+CONFIG_BITREVERSE=y
+CONFIG_FONT_SUPPORT=y
+CONFIG_I2C=y
# CONFIG_MIPS is not set
-CONFIG_EFI=y
-# CONFIG_SOC_DRA7XX is not set
+# CONFIG_ARCH_TEGRA is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_STA2X11 is not set
+# CONFIG_PWM_OMAP_DMTIMER is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_BLACKFIN is not set
+# CONFIG_ARCH_OMAP2 is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MULTIPLEXER is not set
+CONFIG_COMMON_CLK=y
+# CONFIG_ARCH_MESON is not set
+# CONFIG_ARCH_ROCKCHIP is not set
+# CONFIG_ARCH_OMAP4 is not set
+CONFIG_NEW_LEDS=y
+# CONFIG_ARCH_QCOM is not set
+# CONFIG_ARCH_STM32 is not set
+# CONFIG_ARCH_MEDIATEK is not set
+# CONFIG_ARCH_DAVINCI is not set
+CONFIG_INET=y
+# CONFIG_SOC_IMX27 is not set
+CONFIG_X86=y
+# CONFIG_SOC_EXYNOS4212 is not set
+# CONFIG_ARCH_SHMOBILE is not set
+# CONFIG_VIDEO_V4L1 is not set
+# CONFIG_OMAP2_VRFB is not set
+CONFIG_INPUT=y
+# CONFIG_RPMSG is not set
+# CONFIG_MTK_IOMMU is not set
+CONFIG_SND_SOC=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_OMAP_IOMMU is not set
+# CONFIG_ARCH_OMAP2PLUS is not set
+CONFIG_MMU=y
+# CONFIG_SOC_EXYNOS5250 is not set
+# CONFIG_REGMAP_MMIO is not set
+CONFIG_RATIONAL=y
+# CONFIG_SND_ISA is not set
+CONFIG_HAS_IOMEM=y
+CONFIG_HDMI=y
+# CONFIG_SOC_EXYNOS4412 is not set
+# CONFIG_ARCH_AT91 is not set
# CONFIG_VIDEO_KERNEL_VERSION is not set
+CONFIG_RC_CORE=m
+CONFIG_RC_MAP=m
+CONFIG_RC_DECODERS=y
+CONFIG_LIRC=m
+CONFIG_IR_LIRC_CODEC=m
+CONFIG_IR_NEC_DECODER=m
+CONFIG_IR_RC5_DECODER=m
+CONFIG_IR_RC6_DECODER=m
+CONFIG_IR_JVC_DECODER=m
+CONFIG_IR_SONY_DECODER=m
+CONFIG_IR_SANYO_DECODER=m
+CONFIG_IR_SHARP_DECODER=m
+CONFIG_IR_MCE_KBD_DECODER=m
+CONFIG_IR_XMP_DECODER=m
+CONFIG_RC_DEVICES=y
+CONFIG_RC_ATI_REMOTE=m
+CONFIG_IR_ENE=m
+CONFIG_IR_IMON=m
+CONFIG_IR_MCEUSB=m
+CONFIG_IR_ITE_CIR=m
+CONFIG_IR_FINTEK=m
+CONFIG_IR_NUVOTON=m
+CONFIG_IR_REDRAT3=m
+CONFIG_IR_STREAMZAP=m
+CONFIG_IR_WINBOND_CIR=m
+CONFIG_IR_IGORPLUGUSB=m
+CONFIG_IR_IGUANA=m
+CONFIG_IR_TTUSBIR=m
+CONFIG_RC_LOOPBACK=m
+CONFIG_IR_SERIAL=m
+CONFIG_IR_SERIAL_TRANSMITTER=y
+# CONFIG_IR_SIR is not set
CONFIG_MEDIA_SUPPORT=m
#
# Multimedia core support
#
-CONFIG_MEDIA_CAMERA_SUPPORT=y
+# CONFIG_MEDIA_CAMERA_SUPPORT is not set
CONFIG_MEDIA_ANALOG_TV_SUPPORT=y
CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y
# CONFIG_MEDIA_RADIO_SUPPORT is not set
# CONFIG_MEDIA_SDR_SUPPORT is not set
-CONFIG_MEDIA_RC_SUPPORT=y
# CONFIG_MEDIA_CEC_SUPPORT is not set
# CONFIG_MEDIA_CONTROLLER is not set
CONFIG_VIDEO_DEV=m
@@ -170,54 +211,8 @@ CONFIG_DVB_DYNAMIC_MINORS=y
#
# Media drivers
#
-CONFIG_RC_CORE=m
-CONFIG_RC_MAP=m
-CONFIG_RC_DECODERS=y
-CONFIG_LIRC=m
-CONFIG_IR_LIRC_CODEC=m
-CONFIG_IR_NEC_DECODER=m
-CONFIG_IR_RC5_DECODER=m
-CONFIG_IR_RC6_DECODER=m
-CONFIG_IR_JVC_DECODER=m
-CONFIG_IR_SONY_DECODER=m
-CONFIG_IR_SANYO_DECODER=m
-CONFIG_IR_SHARP_DECODER=m
-CONFIG_IR_MCE_KBD_DECODER=m
-CONFIG_IR_XMP_DECODER=m
-CONFIG_RC_DEVICES=y
-CONFIG_RC_ATI_REMOTE=m
-CONFIG_IR_ENE=m
-CONFIG_IR_HIX5HD2=m
-CONFIG_IR_IMON=m
-CONFIG_IR_MCEUSB=m
-CONFIG_IR_ITE_CIR=m
-CONFIG_IR_FINTEK=m
-CONFIG_IR_NUVOTON=m
-CONFIG_IR_REDRAT3=m
-CONFIG_IR_STREAMZAP=m
-CONFIG_IR_WINBOND_CIR=m
-CONFIG_IR_IGORPLUGUSB=m
-CONFIG_IR_IGUANA=m
-CONFIG_IR_TTUSBIR=m
-CONFIG_RC_LOOPBACK=m
-CONFIG_IR_GPIO_CIR=m
-CONFIG_IR_SERIAL=m
-CONFIG_IR_SERIAL_TRANSMITTER=y
-# CONFIG_IR_SIR is not set
CONFIG_MEDIA_USB_SUPPORT=y
-#
-# Webcam devices
-#
-# CONFIG_USB_VIDEO_CLASS is not set
-# CONFIG_USB_GSPCA is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_VIDEO_CPIA2 is not set
-# CONFIG_USB_ZR364XX is not set
-# CONFIG_USB_STKWEBCAM is not set
-# CONFIG_USB_S2255 is not set
-# CONFIG_VIDEO_USBTV is not set
-
#
# Analog TV USB devices
#
@@ -292,6 +287,7 @@ CONFIG_DVB_USB_TBS5881=m
CONFIG_DVB_USB_TBS5520=m
CONFIG_DVB_USB_TBS5927=m
CONFIG_DVB_USB_TBS5520SE=m
+CONFIG_DVB_USB_TBS5580=m
CONFIG_DVB_USB_CYCITV=m
CONFIG_DVB_USB_V2=m
CONFIG_DVB_USB_AF9015=m
@@ -323,9 +319,6 @@ CONFIG_VIDEO_EM28XX_V4L2=m
CONFIG_VIDEO_EM28XX_DVB=m
CONFIG_VIDEO_EM28XX_RC=m
# CONFIG_MEDIA_PCI_SUPPORT is not set
-# CONFIG_V4L_PLATFORM_DRIVERS is not set
-# CONFIG_V4L_MEM2MEM_DRIVERS is not set
-# CONFIG_V4L_TEST_DRIVERS is not set
# CONFIG_DVB_PLATFORM_DRIVERS is not set
#
@@ -390,9 +383,6 @@ CONFIG_VIDEO_CX25840=m
#
# Camera sensor devices
#
-CONFIG_VIDEO_OV2640=m
-CONFIG_VIDEO_OV7640=m
-CONFIG_VIDEO_MT9V011=m
#
# Flash devices
@@ -406,6 +396,10 @@ CONFIG_VIDEO_MT9V011=m
# Audio/Video compression chips
#
+#
+# SDR tuner chips
+#
+
#
# Miscellaneous helper chips
#
@@ -415,6 +409,7 @@ CONFIG_VIDEO_MT9V011=m
#
CONFIG_MEDIA_TUNER=m
CONFIG_MEDIA_TUNER_SIMPLE=m
+CONFIG_MEDIA_TUNER_TDA18250=m
CONFIG_MEDIA_TUNER_TDA8290=m
CONFIG_MEDIA_TUNER_TDA827X=m
CONFIG_MEDIA_TUNER_TDA18271=m
@@ -573,7 +568,7 @@ CONFIG_DVB_M88RS2000=m
CONFIG_DVB_AF9033=m
CONFIG_DVB_TAS2101=m
CONFIG_DVB_AVL6882=m
-CONFIG_DVB_STV0910=m
+CONFIG_DVB_STV091X=m
CONFIG_DVB_SI2183=m
#
@@ -589,8 +584,3 @@ CONFIG_MISC_DEVICES=y
#
CONFIG_ALTERA_STAPL=m
# CONFIG_STAGING is not set
-
-# RPi DVB Hat
-CONFIG_DVB_CXD2820R=m
-CONFIG_DVB_CXD2841ER=m
-CONFIG_DVB_CXD2880=m
diff --git a/packages/linux-driver-addons/dvb/crazycat/icon/icon.png b/packages/linux-driver-addons/dvb/crazycat/icon/icon.png
new file mode 100644
index 0000000000..22a6c6a0d9
Binary files /dev/null and b/packages/linux-driver-addons/dvb/crazycat/icon/icon.png differ
diff --git a/packages/linux-drivers/media_build/package.mk b/packages/linux-driver-addons/dvb/crazycat/package.mk
similarity index 75%
rename from packages/linux-drivers/media_build/package.mk
rename to packages/linux-driver-addons/dvb/crazycat/package.mk
index ed3ef6ba34..ebbb4e42f6 100644
--- a/packages/linux-drivers/media_build/package.mk
+++ b/packages/linux-driver-addons/dvb/crazycat/package.mk
@@ -16,9 +16,9 @@
# along with LibreELEC. If not, see .
################################################################################
-PKG_NAME="media_build"
-PKG_VERSION="2017-06-20-rpi"
-PKG_SHA256="ff30bf1ee9fe342649ad80c9072ab4d37238d05680da850828f6d6c1d6b2e6d4"
+PKG_NAME="crazycat"
+PKG_VERSION="2017-11-13"
+PKG_SHA256="14d951eb8d40cee40d601d7c737bca07171d8b4f201d63d5e70a24c4841f9d73"
PKG_ARCH="any"
PKG_LICENSE="GPL"
PKG_SITE="https://github.com/crazycat69/linux_media"
@@ -26,10 +26,14 @@ PKG_URL="$DISTRO_SRC/$PKG_NAME-$PKG_VERSION.tar.xz"
PKG_DEPENDS_TARGET="toolchain linux"
PKG_BUILD_DEPENDS_TARGET="toolchain linux"
PKG_NEED_UNPACK="$LINUX_DEPENDS"
-PKG_SECTION="driver"
-PKG_SHORTDESC="DVB drivers that replace the version shipped with the kernel"
-PKG_LONGDESC="DVB drivers that replace the version shipped with the kernel"
-PKG_IS_KERNEL_PKG="yes"
+PKG_SECTION="driver.dvb"
+PKG_LONGDESC="DVB driver for TBS cards with CrazyCats additions."
+
+PKG_IS_ADDON="yes"
+PKG_ADDON_IS_STANDALONE="yes"
+PKG_ADDON_NAME="DVB drivers for TBS (CrazyCat)"
+PKG_ADDON_TYPE="xbmc.service"
+PKG_ADDON_VERSION="${ADDON_VERSION}.${PKG_REV}"
pre_make_target() {
export KERNEL_VER=$(get_module_dir)
@@ -40,7 +44,7 @@ make_target() {
make untar
# copy config file
- if [ "$PROJECT" = Generic ] || [ "$PROJECT" = Virtual ]; then
+ if [ "$PROJECT" = Generic ]; then
if [ -f $PKG_DIR/config/generic.config ]; then
cp $PKG_DIR/config/generic.config v4l/.config
fi
@@ -55,6 +59,5 @@ make_target() {
}
makeinstall_target() {
- mkdir -p $INSTALL/$(get_full_module_dir)/updates
- find $PKG_BUILD/v4l/ -name \*.ko -exec cp {} $INSTALL/$(get_full_module_dir)/updates \;
+ install_driver_addon_files "$PKG_BUILD/v4l/"
}
diff --git a/packages/linux-drivers/media_build/patches/media_build-01-remove-rmmod.pl.patch b/packages/linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-01-remove-rmmod.pl.patch
similarity index 100%
rename from packages/linux-drivers/media_build/patches/media_build-01-remove-rmmod.pl.patch
rename to packages/linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-01-remove-rmmod.pl.patch
diff --git a/packages/linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-02-add-to-backports.patch b/packages/linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-02-add-to-backports.patch
new file mode 100644
index 0000000000..8eec833bde
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-02-add-to-backports.patch
@@ -0,0 +1,11 @@
+--- a/backports/backports.txt
++++ b/backports/backports.txt
+@@ -25,6 +25,8 @@ add api_version.patch
+ add pr_fmt.patch
+ add debug.patch
+ add drx39xxj.patch
++add linux-202-lnbp22_patch_for_more_power_if_rotor.patch
++add linux-220-Xbox-One-DVB-T2-stick-support.patch
+
+ [4.12.255]
+ add v4.12_revert_solo6x10_copykerneluser.patch
diff --git a/packages/linux-driver-addons/dvb/crazycat/source/default.py b/packages/linux-driver-addons/dvb/crazycat/source/default.py
new file mode 100644
index 0000000000..fe3ba645a6
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/crazycat/source/default.py
@@ -0,0 +1,17 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2017-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch b/packages/linux-driver-addons/dvb/crazycat/sources/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch
similarity index 100%
rename from packages/linux-drivers/media_build/sources/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch
rename to packages/linux-driver-addons/dvb/crazycat/sources/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch
diff --git a/packages/linux-driver-addons/dvb/crazycat/sources/backports/linux-220-Xbox-One-DVB-T2-stick-support.patch b/packages/linux-driver-addons/dvb/crazycat/sources/backports/linux-220-Xbox-One-DVB-T2-stick-support.patch
new file mode 100644
index 0000000000..615c8d8cfb
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/crazycat/sources/backports/linux-220-Xbox-One-DVB-T2-stick-support.patch
@@ -0,0 +1,1386 @@
+From b8ca04e7037433d13b6a526123d16493eff74bd0 Mon Sep 17 00:00:00 2001
+From: Olli Salonen
+Date: Thu, 23 Nov 2017 08:36:10 +0200
+Subject: Xbox ONE DVB-C/T/T2 USB Tuner support
+
+diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
+index 7678319..e1a043b 100644
+--- a/drivers/media/dvb-core/dvb-usb-ids.h
++++ b/drivers/media/dvb-core/dvb-usb-ids.h
+@@ -80,6 +80,7 @@
+ #define USB_VID_AZUREWAVE 0x13d3
+ #define USB_VID_TECHNISAT 0x14f7
+ #define USB_VID_HAMA 0x147f
++#define USB_VID_MICROSOFT 0x045e
+
+ /* Product IDs */
+ #define USB_PID_ADSTECH_USB2_COLD 0xa333
+@@ -418,4 +419,5 @@
+ #define USB_PID_WINTV_SOLOHD 0x0264
+ #define USB_PID_EVOLVEO_XTRATV_STICK 0xa115
+ #define USB_PID_HAMA_DVBT_HYBRID 0x2758
++#define USB_PID_XBOX_ONE_TUNER 0x02d5
+ #endif
+diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
+index 1dc7bb6..0a714ba 100644
+--- a/drivers/media/tuners/Kconfig
++++ b/drivers/media/tuners/Kconfig
+@@ -26,6 +26,13 @@ config MEDIA_TUNER_SIMPLE
+ help
+ Say Y here to include support for various simple tuners.
+
++config MEDIA_TUNER_TDA18250
++ tristate "NXP TDA18250 silicon tuner"
++ depends on MEDIA_SUPPORT && I2C
++ default m if !MEDIA_SUBDRV_AUTOSELECT
++ help
++ Say Y here to include support for TDA18250 tuner.
++
+ config MEDIA_TUNER_TDA8290
+ tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
+ depends on MEDIA_SUPPORT && I2C
+diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
+index ba382f9..aee8801 100644
+--- a/drivers/media/tuners/Makefile
++++ b/drivers/media/tuners/Makefile
+@@ -45,6 +45,7 @@ obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o
+ obj-$(CONFIG_MEDIA_TUNER_AV201X) += av201x.o
+ obj-$(CONFIG_MEDIA_TUNER_R848) += r848.o
+ obj-$(CONFIG_MEDIA_TUNER_STV6120) += stv6120.o
++obj-$(CONFIG_MEDIA_TUNER_TDA18250) += tda18250.o
+
+ ccflags-y += -I$(srctree)/drivers/media/dvb-core
+ ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
+diff --git a/drivers/media/tuners/tda18250.c b/drivers/media/tuners/tda18250.c
+new file mode 100644
+index 0000000..20d12b0
+--- /dev/null
++++ b/drivers/media/tuners/tda18250.c
+@@ -0,0 +1,902 @@
++/*
++ * NXP TDA18250 silicon tuner driver
++ *
++ * Copyright (C) 2017 Olli Salonen
++ *
++ * 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.
++ *
++ */
++
++#include "tda18250_priv.h"
++#include
++
++static const struct dvb_tuner_ops tda18250_ops;
++
++static int tda18250_power_control(struct dvb_frontend *fe,
++ unsigned int power_state)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ int ret;
++ unsigned int utmp;
++
++ dev_dbg(&client->dev, "power state: %d", power_state);
++
++ switch (power_state) {
++ case TDA18250_POWER_NORMAL:
++ ret = regmap_write_bits(dev->regmap, R06_POWER2, 0x07, 0x00);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap, R25_REF, 0xc0, 0xc0);
++ if (ret)
++ goto err;
++ break;
++ case TDA18250_POWER_STANDBY:
++ if (dev->loopthrough) {
++ ret = regmap_write_bits(dev->regmap,
++ R25_REF, 0xc0, 0x80);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap,
++ R06_POWER2, 0x07, 0x02);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap,
++ R10_LT1, 0x80, 0x00);
++ if (ret)
++ goto err;
++ } else {
++ ret = regmap_write_bits(dev->regmap,
++ R25_REF, 0xc0, 0x80);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap,
++ R06_POWER2, 0x07, 0x01);
++ if (ret)
++ goto err;
++ ret = regmap_read(dev->regmap,
++ R0D_AGC12, &utmp);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap,
++ R0D_AGC12, 0x03, 0x03);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap,
++ R10_LT1, 0x80, 0x80);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap,
++ R0D_AGC12, 0x03, utmp & 0x03);
++ if (ret)
++ goto err;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ goto err;
++ }
++
++ return 0;
++err:
++ return ret;
++}
++
++static int tda18250_wait_for_irq(struct dvb_frontend *fe,
++ int maxwait, int step, u8 irq)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ int ret;
++ unsigned long timeout;
++ bool triggered;
++ unsigned int utmp;
++
++ triggered = false;
++ timeout = jiffies + msecs_to_jiffies(maxwait);
++ while (!time_after(jiffies, timeout)) {
++ // check for the IRQ
++ ret = regmap_read(dev->regmap, R08_IRQ1, &utmp);
++ if (ret)
++ goto err;
++ if ((utmp & irq) == irq) {
++ triggered = true;
++ break;
++ }
++ msleep(step);
++ }
++
++ dev_dbg(&client->dev, "waited IRQ (0x%02x) %d ms, triggered: %s", irq,
++ jiffies_to_msecs(jiffies) -
++ (jiffies_to_msecs(timeout) - maxwait),
++ triggered ? "true" : "false");
++
++ if (!triggered)
++ return -ETIMEDOUT;
++
++ return 0;
++err:
++ return ret;
++}
++
++static int tda18250_init(struct dvb_frontend *fe)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ int ret, i;
++
++ /* default values for various regs */
++ static const u8 init_regs[][2] = {
++ { R0C_AGC11, 0xc7 },
++ { R0D_AGC12, 0x5d },
++ { R0E_AGC13, 0x40 },
++ { R0F_AGC14, 0x0e },
++ { R10_LT1, 0x47 },
++ { R11_LT2, 0x4e },
++ { R12_AGC21, 0x26 },
++ { R13_AGC22, 0x60 },
++ { R18_AGC32, 0x37 },
++ { R19_AGC33, 0x09 },
++ { R1A_AGCK, 0x00 },
++ { R1E_WI_FI, 0x29 },
++ { R1F_RF_BPF, 0x06 },
++ { R20_IR_MIX, 0xc6 },
++ { R21_IF_AGC, 0x00 },
++ { R2C_PS1, 0x75 },
++ { R2D_PS2, 0x06 },
++ { R2E_PS3, 0x07 },
++ { R30_RSSI2, 0x0e },
++ { R31_IRQ_CTRL, 0x00 },
++ { R39_SD5, 0x00 },
++ { R3B_REGU, 0x55 },
++ { R3C_RCCAL1, 0xa7 },
++ { R3F_IRCAL2, 0x85 },
++ { R40_IRCAL3, 0x87 },
++ { R41_IRCAL4, 0xc0 },
++ { R43_PD1, 0x40 },
++ { R44_PD2, 0xc0 },
++ { R46_CPUMP, 0x0c },
++ { R47_LNAPOL, 0x64 },
++ { R4B_XTALOSC1, 0x30 },
++ { R59_AGC2_UP2, 0x05 },
++ { R5B_AGC_AUTO, 0x07 },
++ { R5C_AGC_DEBUG, 0x00 },
++ };
++
++ /* crystal related regs depend on frequency */
++ static const u8 xtal_regs[][5] = {
++ /* reg: 4d 4e 4f 50 51 */
++ [TDA18250_XTAL_FREQ_16MHZ] = { 0x3e, 0x80, 0x50, 0x00, 0x20 },
++ [TDA18250_XTAL_FREQ_24MHZ] = { 0x5d, 0xc0, 0xec, 0x00, 0x18 },
++ [TDA18250_XTAL_FREQ_25MHZ] = { 0x61, 0xa8, 0xec, 0x80, 0x19 },
++ [TDA18250_XTAL_FREQ_27MHZ] = { 0x69, 0x78, 0x8d, 0x80, 0x1b },
++ [TDA18250_XTAL_FREQ_30MHZ] = { 0x75, 0x30, 0x8f, 0x00, 0x1e },
++ };
++
++ dev_dbg(&client->dev, "\n");
++
++ ret = tda18250_power_control(fe, TDA18250_POWER_NORMAL);
++ if (ret)
++ goto err;
++
++ msleep(20);
++
++ if (dev->warm)
++ goto warm;
++
++ /* set initial register values */
++ for (i = 0; i < ARRAY_SIZE(init_regs); i++) {
++ ret = regmap_write(dev->regmap, init_regs[i][0],
++ init_regs[i][1]);
++ if (ret)
++ goto err;
++ }
++
++ /* set xtal related regs */
++ ret = regmap_bulk_write(dev->regmap, R4D_XTALFLX1,
++ xtal_regs[dev->xtal_freq], 5);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R10_LT1, 0x80,
++ dev->loopthrough ? 0x00 : 0x80);
++ if (ret)
++ goto err;
++
++ /* clear IRQ */
++ ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_HW_INIT);
++ if (ret)
++ goto err;
++
++ /* start HW init */
++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x70);
++ if (ret)
++ goto err;
++
++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01);
++ if (ret)
++ goto err;
++
++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_HW_INIT);
++ if (ret)
++ goto err;
++
++ /* tuner calibration */
++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x02);
++ if (ret)
++ goto err;
++
++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01);
++ if (ret)
++ goto err;
++
++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_CAL);
++ if (ret)
++ goto err;
++
++ dev->warm = true;
++
++warm:
++ /* power up LNA */
++ ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00);
++ if (ret)
++ goto err;
++
++ return 0;
++err:
++ dev_dbg(&client->dev, "failed=%d", ret);
++ return ret;
++}
++
++static int tda18250_set_agc(struct dvb_frontend *fe)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ int ret;
++ u8 utmp, utmp2;
++
++ dev_dbg(&client->dev, "\n");
++
++ ret = regmap_write_bits(dev->regmap, R1F_RF_BPF, 0x87, 0x06);
++ if (ret)
++ goto err;
++
++ utmp = ((c->frequency < 100000000) &&
++ ((c->delivery_system == SYS_DVBC_ANNEX_A) ||
++ (c->delivery_system == SYS_DVBC_ANNEX_C)) &&
++ (c->bandwidth_hz == 6000000)) ? 0x80 : 0x00;
++ ret = regmap_write(dev->regmap, R5A_H3H5, utmp);
++ if (ret)
++ goto err;
++
++ /* AGC1 */
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ utmp = 4;
++ break;
++ default: /* DVB-C/QAM */
++ switch (c->bandwidth_hz) {
++ case 6000000:
++ utmp = (c->frequency < 800000000) ? 6 : 4;
++ break;
++ default: /* 7.935 and 8 MHz */
++ utmp = (c->frequency < 100000000) ? 2 : 3;
++ break;
++ }
++ break;
++ }
++
++ ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x07, utmp);
++ if (ret)
++ goto err;
++
++ /* AGC2 */
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ utmp = (c->frequency < 320000000) ? 20 : 16;
++ utmp2 = (c->frequency < 320000000) ? 22 : 18;
++ break;
++ default: /* DVB-C/QAM */
++ switch (c->bandwidth_hz) {
++ case 6000000:
++ if (c->frequency < 600000000) {
++ utmp = 18;
++ utmp2 = 22;
++ } else if (c->frequency < 800000000) {
++ utmp = 16;
++ utmp2 = 20;
++ } else {
++ utmp = 14;
++ utmp2 = 16;
++ }
++ break;
++ default: /* 7.935 and 8 MHz */
++ utmp = (c->frequency < 320000000) ? 16 : 18;
++ utmp2 = (c->frequency < 320000000) ? 18 : 20;
++ break;
++ }
++ break;
++ }
++ ret = regmap_write_bits(dev->regmap, R58_AGC2_UP1, 0x1f, utmp2+8);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap, R13_AGC22, 0x1f, utmp);
++ if (ret)
++ goto err;
++ ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x1f, utmp2);
++ if (ret)
++ goto err;
++
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ utmp = 98;
++ break;
++ default: /* DVB-C/QAM */
++ utmp = 90;
++ break;
++ }
++ ret = regmap_write_bits(dev->regmap, R16_AGC25, 0xf8, utmp);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R12_AGC21, 0x60,
++ (c->frequency > 800000000) ? 0x40 : 0x20);
++ if (ret)
++ goto err;
++
++ /* AGC3 */
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ utmp = (c->frequency < 320000000) ? 5 : 7;
++ utmp2 = (c->frequency < 320000000) ? 10 : 12;
++ break;
++ default: /* DVB-C/QAM */
++ utmp = 7;
++ utmp2 = 12;
++ break;
++ }
++ ret = regmap_write(dev->regmap, R17_AGC31, (utmp << 4) | utmp2);
++ if (ret)
++ goto err;
++
++ /* S2D */
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ if (c->bandwidth_hz == 8000000)
++ utmp = 0x04;
++ else
++ utmp = (c->frequency < 320000000) ? 0x04 : 0x02;
++ break;
++ default: /* DVB-C/QAM */
++ if (c->bandwidth_hz == 6000000)
++ utmp = ((c->frequency > 172544000) &&
++ (c->frequency < 320000000)) ? 0x04 : 0x02;
++ else /* 7.935 and 8 MHz */
++ utmp = ((c->frequency > 320000000) &&
++ (c->frequency < 600000000)) ? 0x02 : 0x04;
++ break;
++ }
++ ret = regmap_write_bits(dev->regmap, R20_IR_MIX, 0x06, utmp);
++ if (ret)
++ goto err;
++
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ utmp = 0;
++ break;
++ default: /* DVB-C/QAM */
++ utmp = (c->frequency < 600000000) ? 0 : 3;
++ break;
++ }
++ ret = regmap_write_bits(dev->regmap, R16_AGC25, 0x03, utmp);
++ if (ret)
++ goto err;
++
++ utmp = 0x09;
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ if (c->bandwidth_hz == 8000000)
++ utmp = 0x0c;
++ break;
++ default: /* DVB-C/QAM */
++ utmp = 0x0c;
++ break;
++ }
++ ret = regmap_write_bits(dev->regmap, R0F_AGC14, 0x3f, utmp);
++ if (ret)
++ goto err;
++
++ return 0;
++err:
++ dev_dbg(&client->dev, "failed=%d", ret);
++ return ret;
++}
++
++static int tda18250_pll_calc(struct dvb_frontend *fe, u8 *rdiv,
++ u8 *ndiv, u8 *icp)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ int ret;
++ unsigned int uval, exp, lopd, scale;
++ unsigned long fvco;
++
++ ret = regmap_read(dev->regmap, R34_MD1, &uval);
++ if (ret)
++ goto err;
++
++ exp = (uval & 0x70) >> 4;
++ if (exp > 5)
++ exp = 0;
++ lopd = 1 << (exp - 1);
++ scale = uval & 0x0f;
++ fvco = lopd * scale * ((c->frequency / 1000) + dev->if_frequency);
++
++ switch (dev->xtal_freq) {
++ case TDA18250_XTAL_FREQ_16MHZ:
++ *rdiv = 1;
++ *ndiv = 0;
++ *icp = (fvco < 6622000) ? 0x05 : 0x02;
++ break;
++ case TDA18250_XTAL_FREQ_24MHZ:
++ case TDA18250_XTAL_FREQ_25MHZ:
++ *rdiv = 3;
++ *ndiv = 1;
++ *icp = (fvco < 6622000) ? 0x05 : 0x02;
++ break;
++ case TDA18250_XTAL_FREQ_27MHZ:
++ if (fvco < 6643000) {
++ *rdiv = 2;
++ *ndiv = 0;
++ *icp = 0x05;
++ } else if (fvco < 6811000) {
++ *rdiv = 2;
++ *ndiv = 0;
++ *icp = 0x06;
++ } else {
++ *rdiv = 3;
++ *ndiv = 1;
++ *icp = 0x02;
++ }
++ break;
++ case TDA18250_XTAL_FREQ_30MHZ:
++ *rdiv = 2;
++ *ndiv = 0;
++ *icp = (fvco < 6811000) ? 0x05 : 0x02;
++ break;
++ default:
++ return -EINVAL;
++ }
++
++ dev_dbg(&client->dev,
++ "lopd=%d scale=%u fvco=%lu, rdiv=%d ndiv=%d icp=%d",
++ lopd, scale, fvco, *rdiv, *ndiv, *icp);
++ return 0;
++err:
++ return ret;
++}
++
++static int tda18250_set_params(struct dvb_frontend *fe)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ u32 if_khz;
++ int ret;
++ unsigned int i, j;
++ u8 utmp;
++ u8 buf[3];
++
++ #define REG 0
++ #define MASK 1
++ #define DVBT_6 2
++ #define DVBT_7 3
++ #define DVBT_8 4
++ #define DVBC_6 5
++ #define DVBC_8 6
++ #define ATSC 7
++
++ static const u8 delsys_params[][16] = {
++ [REG] = { 0x22, 0x23, 0x24, 0x21, 0x0d, 0x0c, 0x0f, 0x14,
++ 0x0e, 0x12, 0x58, 0x59, 0x1a, 0x19, 0x1e, 0x30 },
++ [MASK] = { 0x77, 0xff, 0xff, 0x87, 0xf0, 0x78, 0x07, 0xe0,
++ 0x60, 0x0f, 0x60, 0x0f, 0x33, 0x30, 0x80, 0x06 },
++ [DVBT_6] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0,
++ 0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 },
++ [DVBT_7] = { 0x52, 0x03, 0x85, 0x82, 0x40, 0x48, 0x01, 0xe0,
++ 0x60, 0x0f, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 },
++ [DVBT_8] = { 0x53, 0x03, 0x87, 0x82, 0x40, 0x48, 0x06, 0xe0,
++ 0x60, 0x07, 0x60, 0x05, 0x03, 0x10, 0x00, 0x04 },
++ [DVBC_6] = { 0x32, 0x05, 0x86, 0x82, 0x50, 0x00, 0x06, 0x60,
++ 0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 },
++ [DVBC_8] = { 0x53, 0x03, 0x88, 0x82, 0x50, 0x00, 0x06, 0x60,
++ 0x40, 0x0e, 0x60, 0x05, 0x33, 0x10, 0x00, 0x04 },
++ [ATSC] = { 0x51, 0x03, 0x83, 0x82, 0x40, 0x48, 0x01, 0xe0,
++ 0x40, 0x0e, 0x60, 0x05, 0x03, 0x00, 0x80, 0x04 },
++ };
++
++ dev_dbg(&client->dev,
++ "delivery_system=%d frequency=%u bandwidth_hz=%u",
++ c->delivery_system, c->frequency, c->bandwidth_hz);
++
++
++ switch (c->delivery_system) {
++ case SYS_ATSC:
++ j = ATSC;
++ if_khz = dev->if_atsc;
++ break;
++ case SYS_DVBT:
++ case SYS_DVBT2:
++ if (c->bandwidth_hz == 0) {
++ ret = -EINVAL;
++ goto err;
++ } else if (c->bandwidth_hz <= 6000000) {
++ j = DVBT_6;
++ if_khz = dev->if_dvbt_6;
++ } else if (c->bandwidth_hz <= 7000000) {
++ j = DVBT_7;
++ if_khz = dev->if_dvbt_7;
++ } else if (c->bandwidth_hz <= 8000000) {
++ j = DVBT_8;
++ if_khz = dev->if_dvbt_8;
++ } else {
++ ret = -EINVAL;
++ goto err;
++ }
++ break;
++ case SYS_DVBC_ANNEX_A:
++ case SYS_DVBC_ANNEX_C:
++ if (c->bandwidth_hz == 0) {
++ ret = -EINVAL;
++ goto err;
++ } else if (c->bandwidth_hz <= 6000000) {
++ j = DVBC_6;
++ if_khz = dev->if_dvbc_6;
++ } else if (c->bandwidth_hz <= 8000000) {
++ j = DVBC_8;
++ if_khz = dev->if_dvbc_8;
++ } else {
++ ret = -EINVAL;
++ goto err;
++ }
++ break;
++ default:
++ ret = -EINVAL;
++ dev_err(&client->dev, "unsupported delivery system=%d",
++ c->delivery_system);
++ goto err;
++ }
++
++ /* set delivery system dependent registers */
++ for (i = 0; i < 16; i++) {
++ ret = regmap_write_bits(dev->regmap, delsys_params[REG][i],
++ delsys_params[MASK][i], delsys_params[j][i]);
++ if (ret)
++ goto err;
++ }
++
++ /* set IF if needed */
++ if (dev->if_frequency != if_khz) {
++ utmp = DIV_ROUND_CLOSEST(if_khz, 50);
++ ret = regmap_write(dev->regmap, R26_IF, utmp);
++ if (ret)
++ goto err;
++ dev->if_frequency = if_khz;
++ dev_dbg(&client->dev, "set IF=%u kHz", if_khz);
++
++ }
++
++ ret = tda18250_set_agc(fe);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x01);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x00);
++ if (ret)
++ goto err;
++
++ /* set frequency */
++ buf[0] = ((c->frequency / 1000) >> 16) & 0xff;
++ buf[1] = ((c->frequency / 1000) >> 8) & 0xff;
++ buf[2] = ((c->frequency / 1000) >> 0) & 0xff;
++ ret = regmap_bulk_write(dev->regmap, R27_RF1, buf, 3);
++ if (ret)
++ goto err;
++
++ ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE);
++ if (ret)
++ goto err;
++
++ /* initial tune */
++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x01);
++ if (ret)
++ goto err;
++
++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01);
++ if (ret)
++ goto err;
++
++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE);
++ if (ret)
++ goto err;
++
++ /* calc ndiv and rdiv */
++ ret = tda18250_pll_calc(fe, &buf[0], &buf[1], &buf[2]);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R4F_XTALFLX3, 0xe0,
++ (buf[0] << 6) | (buf[1] << 5));
++ if (ret)
++ goto err;
++
++ /* clear IRQ */
++ ret = regmap_write(dev->regmap, R0A_IRQ3, TDA18250_IRQ_TUNE);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, 0x00);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R39_SD5, 0x03, 0x00);
++ if (ret)
++ goto err;
++
++ /* tune again */
++ ret = regmap_write(dev->regmap, R2A_MSM1, 0x01); /* tune */
++ if (ret)
++ goto err;
++
++ ret = regmap_write(dev->regmap, R2B_MSM2, 0x01); /* go */
++ if (ret)
++ goto err;
++
++ ret = tda18250_wait_for_irq(fe, 500, 10, TDA18250_IRQ_TUNE);
++ if (ret)
++ goto err;
++
++ /* pll locking */
++ msleep(20);
++
++ ret = regmap_write_bits(dev->regmap, R2B_MSM2, 0x04, 0x04);
++ if (ret)
++ goto err;
++
++ msleep(20);
++
++ /* restore AGCK */
++ ret = regmap_write_bits(dev->regmap, R1A_AGCK, 0x03, 0x03);
++ if (ret)
++ goto err;
++
++ ret = regmap_write_bits(dev->regmap, R14_AGC23, 0x40, 0x40);
++ if (ret)
++ goto err;
++
++ /* charge pump */
++ ret = regmap_write_bits(dev->regmap, R46_CPUMP, 0x07, buf[2]);
++
++ return 0;
++err:
++ return ret;
++}
++
++static int tda18250_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++
++ *frequency = dev->if_frequency * 1000;
++ return 0;
++}
++
++static int tda18250_sleep(struct dvb_frontend *fe)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ int ret;
++
++ dev_dbg(&client->dev, "\n");
++
++ /* power down LNA */
++ ret = regmap_write_bits(dev->regmap, R0C_AGC11, 0x80, 0x00);
++ if (ret)
++ return ret;
++
++ /* set if freq to 0 in order to make sure it's set after wake up */
++ dev->if_frequency = 0;
++
++ ret = tda18250_power_control(fe, TDA18250_POWER_STANDBY);
++ return ret;
++}
++
++static const struct dvb_tuner_ops tda18250_ops = {
++ .info = {
++ .name = "NXP TDA18250",
++ .frequency_min = 42000000,
++ .frequency_max = 870000000,
++ },
++
++ .init = tda18250_init,
++ .set_params = tda18250_set_params,
++ .get_if_frequency = tda18250_get_if_frequency,
++ .sleep = tda18250_sleep,
++};
++
++static int tda18250_probe(struct i2c_client *client,
++ const struct i2c_device_id *id)
++{
++ struct tda18250_config *cfg = client->dev.platform_data;
++ struct dvb_frontend *fe = cfg->fe;
++ struct tda18250_dev *dev;
++ int ret;
++ unsigned char chip_id[3];
++
++ /* some registers are always read from HW */
++ static const struct regmap_range tda18250_yes_ranges[] = {
++ regmap_reg_range(R05_POWER1, R0B_IRQ4),
++ regmap_reg_range(R21_IF_AGC, R21_IF_AGC),
++ regmap_reg_range(R2A_MSM1, R2B_MSM2),
++ regmap_reg_range(R2F_RSSI1, R31_IRQ_CTRL),
++ };
++
++ static const struct regmap_access_table tda18250_volatile_table = {
++ .yes_ranges = tda18250_yes_ranges,
++ .n_yes_ranges = ARRAY_SIZE(tda18250_yes_ranges),
++ };
++
++ static const struct regmap_config tda18250_regmap_config = {
++ .reg_bits = 8,
++ .val_bits = 8,
++ .max_register = TDA18250_NUM_REGS - 1,
++ .volatile_table = &tda18250_volatile_table,
++ };
++
++ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
++ if (!dev) {
++ ret = -ENOMEM;
++ goto err;
++ }
++
++ i2c_set_clientdata(client, dev);
++
++ dev->fe = cfg->fe;
++ dev->loopthrough = cfg->loopthrough;
++ if (cfg->xtal_freq < TDA18250_XTAL_FREQ_MAX) {
++ dev->xtal_freq = cfg->xtal_freq;
++ } else {
++ ret = -EINVAL;
++ dev_err(&client->dev, "xtal_freq invalid=%d", cfg->xtal_freq);
++ goto err_kfree;
++ }
++ dev->if_dvbt_6 = cfg->if_dvbt_6;
++ dev->if_dvbt_7 = cfg->if_dvbt_7;
++ dev->if_dvbt_8 = cfg->if_dvbt_8;
++ dev->if_dvbc_6 = cfg->if_dvbc_6;
++ dev->if_dvbc_8 = cfg->if_dvbc_8;
++ dev->if_atsc = cfg->if_atsc;
++
++ dev->if_frequency = 0;
++ dev->warm = false;
++
++ dev->regmap = devm_regmap_init_i2c(client, &tda18250_regmap_config);
++ if (IS_ERR(dev->regmap)) {
++ ret = PTR_ERR(dev->regmap);
++ goto err_kfree;
++ }
++
++ /* read the three chip ID registers */
++ regmap_bulk_read(dev->regmap, R00_ID1, &chip_id, 3);
++ dev_dbg(&client->dev, "chip_id=%02x:%02x:%02x",
++ chip_id[0], chip_id[1], chip_id[2]);
++
++ switch (chip_id[0]) {
++ case 0xc7:
++ dev->slave = false;
++ break;
++ case 0x47:
++ dev->slave = true;
++ break;
++ default:
++ ret = -ENODEV;
++ goto err_kfree;
++ }
++
++ if (chip_id[1] != 0x4a) {
++ ret = -ENODEV;
++ goto err_kfree;
++ }
++
++ switch (chip_id[2]) {
++ case 0x20:
++ dev_info(&client->dev,
++ "NXP TDA18250AHN/%s successfully identified",
++ dev->slave ? "S" : "M");
++ break;
++ case 0x21:
++ dev_info(&client->dev,
++ "NXP TDA18250BHN/%s successfully identified",
++ dev->slave ? "S" : "M");
++ break;
++ default:
++ ret = -ENODEV;
++ goto err_kfree;
++ }
++
++ fe->tuner_priv = client;
++ memcpy(&fe->ops.tuner_ops, &tda18250_ops,
++ sizeof(struct dvb_tuner_ops));
++
++ /* put the tuner in standby */
++ tda18250_power_control(fe, TDA18250_POWER_STANDBY);
++
++ return 0;
++err_kfree:
++ kfree(dev);
++err:
++ dev_dbg(&client->dev, "failed=%d", ret);
++ return ret;
++}
++
++static int tda18250_remove(struct i2c_client *client)
++{
++ struct tda18250_dev *dev = i2c_get_clientdata(client);
++ struct dvb_frontend *fe = dev->fe;
++
++ dev_dbg(&client->dev, "\n");
++
++ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
++ fe->tuner_priv = NULL;
++ kfree(dev);
++
++ return 0;
++}
++
++static const struct i2c_device_id tda18250_id_table[] = {
++ {"tda18250", 0},
++ {}
++};
++MODULE_DEVICE_TABLE(i2c, tda18250_id_table);
++
++static struct i2c_driver tda18250_driver = {
++ .driver = {
++ .name = "tda18250",
++ },
++ .probe = tda18250_probe,
++ .remove = tda18250_remove,
++ .id_table = tda18250_id_table,
++};
++
++module_i2c_driver(tda18250_driver);
++
++MODULE_DESCRIPTION("NXP TDA18250 silicon tuner driver");
++MODULE_AUTHOR("Olli Salonen ");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/media/tuners/tda18250.h b/drivers/media/tuners/tda18250.h
+new file mode 100644
+index 0000000..fb56906
+--- /dev/null
++++ b/drivers/media/tuners/tda18250.h
+@@ -0,0 +1,51 @@
++/*
++ * NXP TDA18250BHN silicon tuner driver
++ *
++ * Copyright (C) 2017 Olli Salonen
++ *
++ * 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.
++ */
++
++#ifndef TDA18250_H
++#define TDA18250_H
++
++#include
++#include
++#include "dvb_frontend.h"
++
++#define TDA18250_XTAL_FREQ_16MHZ 0
++#define TDA18250_XTAL_FREQ_24MHZ 1
++#define TDA18250_XTAL_FREQ_25MHZ 2
++#define TDA18250_XTAL_FREQ_27MHZ 3
++#define TDA18250_XTAL_FREQ_30MHZ 4
++#define TDA18250_XTAL_FREQ_MAX 5
++
++struct tda18250_config {
++ u16 if_dvbt_6;
++ u16 if_dvbt_7;
++ u16 if_dvbt_8;
++ u16 if_dvbc_6;
++ u16 if_dvbc_8;
++ u16 if_atsc;
++ u8 xtal_freq;
++ bool loopthrough;
++
++ /*
++ * frontend
++ */
++ struct dvb_frontend *fe;
++
++#if defined(CONFIG_MEDIA_CONTROLLER)
++ struct media_device *mdev;
++#endif
++};
++
++#endif
+diff --git a/drivers/media/tuners/tda18250_priv.h b/drivers/media/tuners/tda18250_priv.h
+new file mode 100644
+index 0000000..4a6f801
+--- /dev/null
++++ b/drivers/media/tuners/tda18250_priv.h
+@@ -0,0 +1,145 @@
++/*
++ * NXP TDA18250BHN silicon tuner driver
++ *
++ * Copyright (C) 2017 Olli Salonen
++ *
++ * 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.
++ */
++
++#ifndef TDA18250_PRIV_H
++#define TDA18250_PRIV_H
++
++#include "tda18250.h"
++
++#define R00_ID1 0x00 /* ID byte 1 */
++#define R01_ID2 0x01 /* ID byte 2 */
++#define R02_ID3 0x02 /* ID byte 3 */
++#define R03_THERMO1 0x03 /* Thermo byte 1 */
++#define R04_THERMO2 0x04 /* Thermo byte 2 */
++#define R05_POWER1 0x05 /* Power byte 1 */
++#define R06_POWER2 0x06 /* Power byte 2 */
++#define R07_GPIO 0x07 /* GPIO */
++#define R08_IRQ1 0x08 /* IRQ */
++#define R09_IRQ2 0x09 /* IRQ */
++#define R0A_IRQ3 0x0a /* IRQ */
++#define R0B_IRQ4 0x0b /* IRQ */
++#define R0C_AGC11 0x0c /* AGC1 byte 1 */
++#define R0D_AGC12 0x0d /* AGC1 byte 2 */
++#define R0E_AGC13 0x0e /* AGC1 byte 3 */
++#define R0F_AGC14 0x0f /* AGC1 byte 4 */
++#define R10_LT1 0x10 /* LT byte 1 */
++#define R11_LT2 0x11 /* LT byte 2 */
++#define R12_AGC21 0x12 /* AGC2 byte 1 */
++#define R13_AGC22 0x13 /* AGC2 byte 2 */
++#define R14_AGC23 0x14 /* AGC2 byte 3 */
++#define R15_AGC24 0x15 /* AGC2 byte 4 */
++#define R16_AGC25 0x16 /* AGC2 byte 5 */
++#define R17_AGC31 0x17 /* AGC3 byte 1 */
++#define R18_AGC32 0x18 /* AGC3 byte 2 */
++#define R19_AGC33 0x19 /* AGC3 byte 3 */
++#define R1A_AGCK 0x1a
++#define R1B_GAIN1 0x1b
++#define R1C_GAIN2 0x1c
++#define R1D_GAIN3 0x1d
++#define R1E_WI_FI 0x1e /* Wireless Filter */
++#define R1F_RF_BPF 0x1f /* RF Band Pass Filter */
++#define R20_IR_MIX 0x20 /* IR Mixer */
++#define R21_IF_AGC 0x21
++#define R22_IF1 0x22 /* IF byte 1 */
++#define R23_IF2 0x23 /* IF byte 2 */
++#define R24_IF3 0x24 /* IF byte 3 */
++#define R25_REF 0x25 /* reference byte */
++#define R26_IF 0x26 /* IF frequency */
++#define R27_RF1 0x27 /* RF frequency byte 1 */
++#define R28_RF2 0x28 /* RF frequency byte 2 */
++#define R29_RF3 0x29 /* RF frequency byte 3 */
++#define R2A_MSM1 0x2a
++#define R2B_MSM2 0x2b
++#define R2C_PS1 0x2c /* power saving mode byte 1 */
++#define R2D_PS2 0x2d /* power saving mode byte 2 */
++#define R2E_PS3 0x2e /* power saving mode byte 3 */
++#define R2F_RSSI1 0x2f
++#define R30_RSSI2 0x30
++#define R31_IRQ_CTRL 0x31
++#define R32_DUMMY 0x32
++#define R33_TEST 0x33
++#define R34_MD1 0x34
++#define R35_SD1 0x35
++#define R36_SD2 0x36
++#define R37_SD3 0x37
++#define R38_SD4 0x38
++#define R39_SD5 0x39
++#define R3A_SD_TEST 0x3a
++#define R3B_REGU 0x3b
++#define R3C_RCCAL1 0x3c
++#define R3D_RCCAL2 0x3d
++#define R3E_IRCAL1 0x3e
++#define R3F_IRCAL2 0x3f
++#define R40_IRCAL3 0x40
++#define R41_IRCAL4 0x41
++#define R42_IRCAL5 0x42
++#define R43_PD1 0x43 /* power down byte 1 */
++#define R44_PD2 0x44 /* power down byte 2 */
++#define R45_PD 0x45 /* power down */
++#define R46_CPUMP 0x46 /* charge pump */
++#define R47_LNAPOL 0x47 /* LNA polar casc */
++#define R48_SMOOTH1 0x48 /* smooth test byte 1 */
++#define R49_SMOOTH2 0x49 /* smooth test byte 2 */
++#define R4A_SMOOTH3 0x4a /* smooth test byte 3 */
++#define R4B_XTALOSC1 0x4b
++#define R4C_XTALOSC2 0x4c
++#define R4D_XTALFLX1 0x4d
++#define R4E_XTALFLX2 0x4e
++#define R4F_XTALFLX3 0x4f
++#define R50_XTALFLX4 0x50
++#define R51_XTALFLX5 0x51
++#define R52_IRLOOP0 0x52
++#define R53_IRLOOP1 0x53
++#define R54_IRLOOP2 0x54
++#define R55_IRLOOP3 0x55
++#define R56_IRLOOP4 0x56
++#define R57_PLL_LOG 0x57
++#define R58_AGC2_UP1 0x58
++#define R59_AGC2_UP2 0x59
++#define R5A_H3H5 0x5a
++#define R5B_AGC_AUTO 0x5b
++#define R5C_AGC_DEBUG 0x5c
++
++#define TDA18250_NUM_REGS 93
++
++#define TDA18250_POWER_STANDBY 0
++#define TDA18250_POWER_NORMAL 1
++
++#define TDA18250_IRQ_CAL 0x81
++#define TDA18250_IRQ_HW_INIT 0x82
++#define TDA18250_IRQ_TUNE 0x88
++
++struct tda18250_dev {
++ struct mutex i2c_mutex;
++ struct dvb_frontend *fe;
++ struct i2c_adapter *i2c;
++ struct regmap *regmap;
++ u8 xtal_freq;
++ /* IF in kHz */
++ u16 if_dvbt_6;
++ u16 if_dvbt_7;
++ u16 if_dvbt_8;
++ u16 if_dvbc_6;
++ u16 if_dvbc_8;
++ u16 if_atsc;
++ u16 if_frequency;
++ bool slave;
++ bool loopthrough;
++ bool warm;
++ u8 regs[TDA18250_NUM_REGS];
++};
++
++#endif
+diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
+index f1a8276..1958d9e 100644
+--- a/drivers/media/usb/dvb-usb/Kconfig
++++ b/drivers/media/usb/dvb-usb/Kconfig
+@@ -86,6 +86,7 @@ config DVB_USB_DIB0700
+ select DVB_USB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
++ select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
+@@ -94,6 +95,7 @@ config DVB_USB_DIB0700
+ select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
++ select MEDIA_TUNER_TDA18250 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
+ USB bridge is also present in devices having the DiB7700 DVB-T-USB
+diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
+index f89ab3b..3a9d4c2 100644
+--- a/drivers/media/usb/dvb-usb/dib0700.h
++++ b/drivers/media/usb/dvb-usb/dib0700.h
+@@ -51,6 +51,8 @@ struct dib0700_state {
+ int (*read_status)(struct dvb_frontend *, enum fe_status *);
+ int (*sleep)(struct dvb_frontend* fe);
+ u8 buf[255];
++ struct i2c_client *i2c_client_demod;
++ struct i2c_client *i2c_client_tuner;
+ };
+
+ extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
+index 1ee7ec5..94bd176 100644
+--- a/drivers/media/usb/dvb-usb/dib0700_core.c
++++ b/drivers/media/usb/dvb-usb/dib0700_core.c
+@@ -911,10 +911,34 @@ static int dib0700_probe(struct usb_interface *intf,
+ return -ENODEV;
+ }
+
++static void dib0700_disconnect(struct usb_interface *intf)
++{
++ struct dvb_usb_device *d = usb_get_intfdata(intf);
++ struct dib0700_state *st = d->priv;
++ struct i2c_client *client;
++
++ /* remove I2C client for tuner */
++ client = st->i2c_client_tuner;
++ if (client) {
++ module_put(client->dev.driver->owner);
++ i2c_unregister_device(client);
++ }
++
++ /* remove I2C client for demodulator */
++ client = st->i2c_client_demod;
++ if (client) {
++ module_put(client->dev.driver->owner);
++ i2c_unregister_device(client);
++ }
++
++ dvb_usb_device_exit(intf);
++}
++
++
+ static struct usb_driver dib0700_driver = {
+ .name = "dvb_usb_dib0700",
+ .probe = dib0700_probe,
+- .disconnect = dvb_usb_device_exit,
++ .disconnect = dib0700_disconnect,
+ .id_table = dib0700_usb_id_table,
+ };
+
+diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
+index 92098c1..8afcd11 100644
+--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
++++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
+@@ -23,6 +23,9 @@
+ #include "dib0090.h"
+ #include "lgdt3305.h"
+ #include "mxl5007t.h"
++#include "mn88472.h"
++#include "tda18250.h"
++
+
+ static int force_lna_activation;
+ module_param(force_lna_activation, int, 0644);
+@@ -3725,6 +3728,90 @@ static int mxl5007t_tuner_attach(struct dvb_usb_adapter *adap)
+ &hcw_mxl5007t_config) == NULL ? -ENODEV : 0;
+ }
+
++static int xbox_one_attach(struct dvb_usb_adapter *adap)
++{
++ struct dib0700_state *st = adap->dev->priv;
++ struct i2c_client *client_demod, *client_tuner;
++ struct dvb_usb_device *d = adap->dev;
++ struct mn88472_config mn88472_config = { };
++ struct tda18250_config tda18250_config;
++ struct i2c_board_info info;
++
++ st->fw_use_new_i2c_api = 1;
++ st->disable_streaming_master_mode = 1;
++
++ /* fe power enable */
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
++ msleep(30);
++ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
++ msleep(30);
++
++ /* demod reset */
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
++ msleep(30);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
++ msleep(30);
++ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
++ msleep(30);
++
++ /* attach demod */
++ mn88472_config.fe = &adap->fe_adap[0].fe;
++ mn88472_config.i2c_wr_max = 22;
++ mn88472_config.xtal = 20500000;
++ mn88472_config.ts_mode = PARALLEL_TS_MODE;
++ mn88472_config.ts_clock = FIXED_TS_CLOCK;
++ memset(&info, 0, sizeof(struct i2c_board_info));
++ strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
++ info.addr = 0x18;
++ info.platform_data = &mn88472_config;
++ request_module(info.type);
++ client_demod = i2c_new_device(&d->i2c_adap, &info);
++ if (client_demod == NULL || client_demod->dev.driver == NULL)
++ goto fail_demod_device;
++ if (!try_module_get(client_demod->dev.driver->owner))
++ goto fail_demod_module;
++
++ st->i2c_client_demod = client_demod;
++
++ adap->fe_adap[0].fe = mn88472_config.get_dvb_frontend(client_demod);
++
++ /* attach tuner */
++ memset(&tda18250_config, 0, sizeof(tda18250_config));
++ tda18250_config.if_dvbt_6 = 3950;
++ tda18250_config.if_dvbt_7 = 4450;
++ tda18250_config.if_dvbt_8 = 4950;
++ tda18250_config.if_dvbc_6 = 4950;
++ tda18250_config.if_dvbc_8 = 4950;
++ tda18250_config.if_atsc = 4079;
++ tda18250_config.loopthrough = true;
++ tda18250_config.xtal_freq = TDA18250_XTAL_FREQ_27MHZ;
++ tda18250_config.fe = adap->fe_adap[0].fe;
++
++ memset(&info, 0, sizeof(struct i2c_board_info));
++ strlcpy(info.type, "tda18250", I2C_NAME_SIZE);
++ info.addr = 0x60;
++ info.platform_data = &tda18250_config;
++
++ request_module(info.type);
++ client_tuner = i2c_new_device(&adap->dev->i2c_adap, &info);
++ if (client_tuner == NULL || client_tuner->dev.driver == NULL)
++ goto fail_tuner_device;
++ if (!try_module_get(client_tuner->dev.driver->owner))
++ goto fail_tuner_module;
++
++ st->i2c_client_tuner = client_tuner;
++ return 0;
++
++fail_tuner_module:
++ i2c_unregister_device(client_tuner);
++fail_tuner_device:
++ module_put(client_demod->dev.driver->owner);
++fail_demod_module:
++ i2c_unregister_device(client_demod);
++fail_demod_device:
++ return -ENODEV;
++}
++
+
+ /* DVB-USB and USB stuff follows */
+ struct usb_device_id dib0700_usb_id_table[] = {
+@@ -3816,7 +3903,8 @@ struct usb_device_id dib0700_usb_id_table[] = {
+ { USB_DEVICE(USB_VID_PCTV, USB_PID_PCTV_2002E_SE) },
+ { USB_DEVICE(USB_VID_PCTV, USB_PID_DIBCOM_STK8096PVR) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK8096PVR) },
+- { USB_DEVICE(USB_VID_HAMA, USB_PID_HAMA_DVBT_HYBRID) },
++/* 85 */{ USB_DEVICE(USB_VID_HAMA, USB_PID_HAMA_DVBT_HYBRID) },
++ { USB_DEVICE(USB_VID_MICROSOFT, USB_PID_XBOX_ONE_TUNER) },
+ { 0 } /* Terminating entry */
+ };
+ MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
+@@ -5040,6 +5128,25 @@ struct dvb_usb_device_properties dib0700_devices[] = {
+ RC_PROTO_BIT_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
++ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
++ .num_adapters = 1,
++ .adapter = {
++ {
++ DIB0700_NUM_FRONTENDS(1),
++ .fe = {{
++ .frontend_attach = xbox_one_attach,
++
++ DIB0700_DEFAULT_STREAMING_CONFIG(0x82),
++ } },
++ },
++ },
++ .num_device_descs = 1,
++ .devices = {
++ { "Microsoft Xbox One Digital TV Tuner",
++ { &dib0700_usb_id_table[86], NULL },
++ { NULL },
++ },
++ },
+ },
+ };
+
+--
+2.14.1
+
diff --git a/packages/linux-driver-addons/dvb/depends/media_tree/package.mk b/packages/linux-driver-addons/dvb/depends/media_tree/package.mk
new file mode 100644
index 0000000000..67f7884d8c
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/depends/media_tree/package.mk
@@ -0,0 +1,42 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2017-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
+
+PKG_NAME="media_tree"
+PKG_VERSION="2017-12-06-b32a2b42f76c"
+PKG_SHA256="90a6b5b015bbb5583a6c72880f8b89ed8b3671ca64c713a00ec3467fbb84cdc4"
+PKG_ARCH="any"
+PKG_LICENSE="GPL"
+PKG_SITE="https://git.linuxtv.org/media_tree.git"
+PKG_URL="http://linuxtv.org/downloads/drivers/linux-media-${PKG_VERSION}.tar.bz2"
+PKG_DEPENDS_TARGET="toolchain"
+PKG_SECTION="driver"
+PKG_LONGDESC="Source of Linux Kernel media_tree subsystem to build with media_build."
+PKG_TOOLCHAIN="manual"
+
+unpack() {
+ mkdir -p $PKG_BUILD/
+ tar -xf $SOURCES/$PKG_NAME/$PKG_NAME-$PKG_VERSION.tar.bz2 -C $PKG_BUILD/
+
+ # hack/workaround for borked upstream kernel/media_build
+ # without removing atomisp there a lot additional includes that
+ # slowdown build process after modpost from 3min to 6min
+ # even if atomisp is disabled via kernel.conf
+ rm -rf $PKG_BUILD/drivers/staging/media/atomisp
+ sed -i 's|^.*drivers/staging/media/atomisp.*$||' \
+ $PKG_BUILD/drivers/staging/media/Kconfig
+}
diff --git a/packages/linux-driver-addons/dvb/digital_devices/changelog.txt b/packages/linux-driver-addons/dvb/digital_devices/changelog.txt
new file mode 100755
index 0000000000..32d81ca428
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/digital_devices/changelog.txt
@@ -0,0 +1,2 @@
+100
+- Initial add-on
diff --git a/packages/linux-driver-addons/dvb/digital_devices/icon/icon.png b/packages/linux-driver-addons/dvb/digital_devices/icon/icon.png
new file mode 100644
index 0000000000..10c6edc267
Binary files /dev/null and b/packages/linux-driver-addons/dvb/digital_devices/icon/icon.png differ
diff --git a/packages/linux-driver-addons/dvb/digital_devices/package.mk b/packages/linux-driver-addons/dvb/digital_devices/package.mk
new file mode 100644
index 0000000000..153ec6902c
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/digital_devices/package.mk
@@ -0,0 +1,45 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2016-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
+
+PKG_NAME="digital_devices"
+PKG_VERSION="0f05b19"
+PKG_SHA256="0f12fa00133eaeb83c4e380cd6e3174d7b399e7e9e5ba8eac0c1ada7579c2c20"
+PKG_ARCH="x86_64"
+PKG_LICENSE="GPL"
+PKG_SITE="https://github.com/DigitalDevices/dddvb/"
+PKG_URL="https://github.com/DigitalDevices/dddvb/archive/${PKG_VERSION}.tar.gz"
+PKG_SOURCE_DIR="dddvb-${PKG_VERSION}*"
+PKG_DEPENDS_TARGET="toolchain linux"
+PKG_BUILD_DEPENDS_TARGET="toolchain linux"
+PKG_NEED_UNPACK="$LINUX_DEPENDS"
+PKG_SECTION="driver.dvb"
+PKG_LONGDESC="DVB driver for Digital Devices cards"
+
+PKG_IS_ADDON="yes"
+PKG_ADDON_IS_STANDALONE="yes"
+PKG_ADDON_NAME="DVB drivers for DigitalDevices"
+PKG_ADDON_TYPE="xbmc.service"
+PKG_ADDON_VERSION="${ADDON_VERSION}.${PKG_REV}"
+
+make_target() {
+ KDIR=$(kernel_path) make
+}
+
+makeinstall_target() {
+ install_driver_addon_files "$PKG_BUILD/ddbridge $PKG_BUILD/dvb-core $PKG_BUILD/frontends"
+}
diff --git a/packages/linux-driver-addons/dvb/digital_devices/source/default.py b/packages/linux-driver-addons/dvb/digital_devices/source/default.py
new file mode 100644
index 0000000000..fe3ba645a6
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/digital_devices/source/default.py
@@ -0,0 +1,17 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2017-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
diff --git a/packages/linux-driver-addons/dvb/hauppauge/changelog.txt b/packages/linux-driver-addons/dvb/hauppauge/changelog.txt
new file mode 100755
index 0000000000..32d81ca428
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/changelog.txt
@@ -0,0 +1,2 @@
+100
+- Initial add-on
diff --git a/packages/linux-driver-addons/dvb/hauppauge/icon/icon.png b/packages/linux-driver-addons/dvb/hauppauge/icon/icon.png
new file mode 100644
index 0000000000..962157e96e
Binary files /dev/null and b/packages/linux-driver-addons/dvb/hauppauge/icon/icon.png differ
diff --git a/packages/linux-driver-addons/dvb/hauppauge/package.mk b/packages/linux-driver-addons/dvb/hauppauge/package.mk
new file mode 100644
index 0000000000..925a8bed6b
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/package.mk
@@ -0,0 +1,51 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2016-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
+
+PKG_NAME="hauppauge"
+PKG_VERSION="f5a5e5e"
+PKG_SHA256="6a3167c9990fa96838f4746861edb4d4e656739ea08d4f993e54becb9f2e9ab2"
+PKG_ARCH="any"
+PKG_LICENSE="GPL"
+PKG_SITE="http://git.linuxtv.org/media_build.git"
+PKG_URL="https://git.linuxtv.org/media_build.git/snapshot/${PKG_VERSION}.tar.gz"
+PKG_SOURCE_DIR="${PKG_VERSION}"
+PKG_DEPENDS_TARGET="toolchain linux media_tree"
+PKG_NEED_UNPACK="$LINUX_DEPENDS media_tree"
+PKG_SECTION="driver.dvb"
+PKG_LONGDESC="DVB drivers for Hauppauge"
+
+PKG_IS_ADDON="yes"
+PKG_ADDON_IS_STANDALONE="yes"
+PKG_ADDON_NAME="DVB drivers for Hauppauge"
+PKG_ADDON_TYPE="xbmc.service"
+PKG_ADDON_VERSION="${ADDON_VERSION}.${PKG_REV}"
+
+pre_make_target() {
+ export KERNEL_VER=$(get_module_dir)
+ export LDFLAGS=""
+}
+
+make_target() {
+ cp -RP $(get_build_dir media_tree)/* $PKG_BUILD/linux
+ make VER=$KERNEL_VER SRCDIR=$(kernel_path) stagingconfig
+ make VER=$KERNEL_VER SRCDIR=$(kernel_path)
+}
+
+makeinstall_target() {
+ install_driver_addon_files "$PKG_BUILD/v4l/"
+}
diff --git a/packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-01-remove-rmmod.pl.patch b/packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-01-remove-rmmod.pl.patch
new file mode 100644
index 0000000000..13435136c9
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-01-remove-rmmod.pl.patch
@@ -0,0 +1,11 @@
+diff --git a/v4l/Makefile b/v4l/Makefile
+--- a/v4l/Makefile
++++ b/v4l/Makefile
+@@ -51,7 +51,6 @@ default:: prepare firmware
+ @echo Kernel build directory is $(OUTDIR)
+ $(MAKE) -C ../linux apply_patches
+ $(MAKE) -C $(OUTDIR) SUBDIRS=$(PWD) $(MYCFLAGS) modules
+- ./scripts/rmmod.pl check
+ # $(MAKE) checkpatch
+
+ mismatch:: prepare firmware
diff --git a/packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-02-add-to-backports.patch b/packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-02-add-to-backports.patch
new file mode 100644
index 0000000000..e5c1152a5c
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-02-add-to-backports.patch
@@ -0,0 +1,11 @@
+--- a/backports/backports.txt
++++ b/backports/backports.txt
+@@ -25,6 +25,8 @@ add api_version.patch
+ add pr_fmt.patch
+ add debug.patch
+ add drx39xxj.patch
++add temp_revert.patch
++add hauppauge.patch
+
+ [4.10.255]
+ add v4.10_sched_signal.patch
diff --git a/packages/linux-driver-addons/dvb/hauppauge/source/default.py b/packages/linux-driver-addons/dvb/hauppauge/source/default.py
new file mode 100644
index 0000000000..fe3ba645a6
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/source/default.py
@@ -0,0 +1,17 @@
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2017-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
diff --git a/packages/linux-driver-addons/dvb/hauppauge/sources/backports/hauppauge.patch b/packages/linux-driver-addons/dvb/hauppauge/sources/backports/hauppauge.patch
new file mode 100644
index 0000000000..1a3520f02f
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/sources/backports/hauppauge.patch
@@ -0,0 +1,3214 @@
+Combined patches from https://github.com/b-rad-NDi/Ubuntu-media-tree-kernel-builder
+to support all kind of Hauppauge DVB cards.
+
+diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
+index 724e9aa..c4fefc2 100644
+--- a/drivers/media/dvb-frontends/lgdt3306a.c
++++ b/drivers/media/dvb-frontends/lgdt3306a.c
+@@ -30,6 +30,17 @@ static int debug;
+ module_param(debug, int, 0644);
+ MODULE_PARM_DESC(debug, "set debug level (info=1, reg=2 (or-able))");
+
++/*
++ * Older drivers treated QAM64 and QAM256 the same; that is the HW always
++ * used "Auto" mode during detection. Setting "forced_manual"=1 allows
++ * the user to treat these modes as separate. For backwards compatibility,
++ * it's off by default. QAM_AUTO can now be specified to achive that
++ * effect even if "forced_manual"=1
++ */
++static int forced_manual;
++module_param(forced_manual, int, 0644);
++MODULE_PARM_DESC(forced_manual, "if set, QAM64 and QAM256 will only lock to modulation specified");
++
+ #define DBG_INFO 1
+ #define DBG_REG 2
+ #define DBG_DUMP 4 /* FGR - comment out to remove dump code */
+@@ -566,7 +577,12 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
+ /* 3. : 64QAM/256QAM detection(manual, auto) */
+ ret = lgdt3306a_read_reg(state, 0x0009, &val);
+ val &= 0xfc;
+- val |= 0x02; /* STDOPDETCMODE[1:0]=1=Manual 2=Auto */
++ /* Check for forced Manual modulation modes; otherwise always "auto" */
++ if(forced_manual && (modulation != QAM_AUTO)){
++ val |= 0x01; /* STDOPDETCMODE[1:0]= 1=Manual */
++ } else {
++ val |= 0x02; /* STDOPDETCMODE[1:0]= 2=Auto */
++ }
+ ret = lgdt3306a_write_reg(state, 0x0009, val);
+ if (lg_chkerr(ret))
+ goto fail;
+@@ -598,6 +614,28 @@ static int lgdt3306a_set_qam(struct lgdt3306a_state *state, int modulation)
+ if (lg_chkerr(ret))
+ goto fail;
+
++ /* 5.1 V0.36 SRDCHKALWAYS : For better QAM detection */
++ ret = lgdt3306a_read_reg(state, 0x000A, &val);
++ val &= 0xFD;
++ val |= 0x02;
++ ret = lgdt3306a_write_reg(state, 0x000A, val);
++ if (lg_chkerr(ret))
++ goto fail;
++
++ /* 5.2 V0.36 Control of "no signal" detector function */
++ ret = lgdt3306a_read_reg(state, 0x2849, &val);
++ val &= 0xDF;
++ ret = lgdt3306a_write_reg(state, 0x2849, val);
++ if (lg_chkerr(ret))
++ goto fail;
++
++ /* 5.3 Fix for Blonder Tongue HDE-2H-QAM and AQM modulators */
++ ret = lgdt3306a_read_reg(state, 0x302B, &val);
++ val &= 0x7F; /* SELFSYNCFINDEN_CQS=0; disable auto reset */
++ ret = lgdt3306a_write_reg(state, 0x302B, val);
++ if (lg_chkerr(ret))
++ goto fail;
++
+ /* 6. Reset */
+ ret = lgdt3306a_soft_reset(state);
+ if (lg_chkerr(ret))
+@@ -620,10 +658,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state,
+ ret = lgdt3306a_set_vsb(state);
+ break;
+ case QAM_64:
+- ret = lgdt3306a_set_qam(state, QAM_64);
+- break;
+ case QAM_256:
+- ret = lgdt3306a_set_qam(state, QAM_256);
++ case QAM_AUTO:
++ ret = lgdt3306a_set_qam(state, p->modulation);
+ break;
+ default:
+ return -EINVAL;
+@@ -650,6 +687,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state,
+ break;
+ case QAM_64:
+ case QAM_256:
++ case QAM_AUTO:
+ break;
+ default:
+ return -EINVAL;
+@@ -704,6 +742,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state,
+ break;
+ case QAM_64:
+ case QAM_256:
++ case QAM_AUTO:
+ /* Auto ok for QAM */
+ ret = lgdt3306a_set_inversion_auto(state, 1);
+ break;
+@@ -727,6 +766,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state,
+ break;
+ case QAM_64:
+ case QAM_256:
++ case QAM_AUTO:
+ if_freq_khz = state->cfg->qam_if_khz;
+ break;
+ default:
+@@ -1585,6 +1625,7 @@ static int lgdt3306a_read_status(struct dvb_frontend *fe,
+ switch (state->current_modulation) {
+ case QAM_256:
+ case QAM_64:
++ case QAM_AUTO:
+ if (lgdt3306a_qam_lock_poll(state) == LG3306_LOCK) {
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+@@ -1628,6 +1669,7 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
+ * Calculate some sort of "strength" from SNR
+ */
+ struct lgdt3306a_state *state = fe->demodulator_priv;
++ u8 val;
+ u16 snr; /* snr_x10 */
+ int ret;
+ u32 ref_snr; /* snr*100 */
+@@ -1640,11 +1682,15 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
+ ref_snr = 1600; /* 16dB */
+ break;
+ case QAM_64:
+- ref_snr = 2200; /* 22dB */
+- break;
+ case QAM_256:
+- ref_snr = 2800; /* 28dB */
+- break;
++ case QAM_AUTO:
++ /* need to know actual modulation to set proper SNR baseline */
++ lgdt3306a_read_reg(state, 0x00a6, &val);
++ if(val & 0x04)
++ ref_snr = 2800; /* QAM-256 28dB */
++ else
++ ref_snr = 2200; /* QAM-64 22dB */
++ break;
+ default:
+ return -EINVAL;
+ }
+@@ -2114,7 +2160,7 @@ static const struct dvb_frontend_ops lgdt3306a_ops = {
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+- .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
++ .caps = FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+ .i2c_gate_ctrl = lgdt3306a_i2c_gate_ctrl,
+ .init = lgdt3306a_init,
+@@ -2177,6 +2223,7 @@ static int lgdt3306a_probe(struct i2c_client *client,
+
+ i2c_set_clientdata(client, fe->demodulator_priv);
+ state = fe->demodulator_priv;
++ state->frontend.ops.release = NULL;
+
+ /* create mux i2c adapter for tuner */
+ state->muxc = i2c_mux_alloc(client->adapter, &client->dev,
+diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
+index 41d9c51..3752bb2 100644
+--- a/drivers/media/dvb-frontends/si2168.c
++++ b/drivers/media/dvb-frontends/si2168.c
+@@ -85,7 +85,7 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+- int ret, i;
++ int ret, i, sys;
+ unsigned int utmp, utmp1, utmp2;
+ struct si2168_cmd cmd;
+
+@@ -96,7 +96,21 @@ static int si2168_read_status(struct dvb_frontend *fe, enum fe_status *status)
+ goto err;
+ }
+
+- switch (c->delivery_system) {
++ memcpy(cmd.args, "\x87\x01", 2);
++ cmd.wlen = 2;
++ cmd.rlen = 8;
++ ret = si2168_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ sys = c->delivery_system;
++ /* check if we found DVBT2 during DVBT tuning */
++ if (sys == SYS_DVBT) {
++ if ((cmd.args[3] & 0x0f) == 7) {
++ sys = SYS_DVBT2;
++ }
++ }
++ switch (sys) {
+ case SYS_DVBT:
+ memcpy(cmd.args, "\xa0\x01", 2);
+ cmd.wlen = 2;
+@@ -211,6 +225,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
++ struct si2168_config *config = client->dev.platform_data;
+ int ret;
+ struct si2168_cmd cmd;
+ u8 bandwidth, delivery_system;
+@@ -228,7 +243,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+- delivery_system = 0x20;
++ delivery_system = 0xf0; /* T/T2 auto-detect is user friendly */
+ break;
+ case SYS_DVBC_ANNEX_A:
+ delivery_system = 0x30;
+@@ -298,6 +313,16 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
+ ret = si2168_cmd_execute(client, &cmd);
+ if (ret)
+ goto err;
++ } else if (c->delivery_system == SYS_DVBT) {
++ /* select Auto PLP */
++ cmd.args[0] = 0x52;
++ cmd.args[1] = 0;
++ cmd.args[2] = 0; /* Auto PLP */
++ cmd.wlen = 3;
++ cmd.rlen = 1;
++ ret = si2168_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
+ }
+
+ memcpy(cmd.args, "\x51\x03", 2);
+@@ -337,6 +362,10 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
+
+ memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
+ cmd.args[4] = delivery_system | bandwidth;
++ if (delivery_system == 0xf0)
++ cmd.args[5] |= 2; /* Auto detect DVB-T/T2 */
++ if (config->inversion) /* inverted spectrum, eg si2157 */
++ cmd.args[5] |= 1;
+ cmd.wlen = 6;
+ cmd.rlen = 4;
+ ret = si2168_cmd_execute(client, &cmd);
+@@ -356,6 +385,8 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
+ }
+
+ memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
++ /* BUGBUG? FW defaults to 1, but windows driver uses 30; above is 0? */
++ cmd.args[5] = 30;
+ cmd.wlen = 6;
+ cmd.rlen = 4;
+ ret = si2168_cmd_execute(client, &cmd);
+diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
+index 3225d0c..0f71233 100644
+--- a/drivers/media/dvb-frontends/si2168.h
++++ b/drivers/media/dvb-frontends/si2168.h
+@@ -45,6 +45,9 @@ struct si2168_config {
+
+ /* TS clock gapped */
+ bool ts_clock_gapped;
++
++ /* Spectral Inversion */
++ bool inversion;
+ };
+
+ #endif
+diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
+index 940c8b1..9d2bb6d 100644
+--- a/drivers/media/i2c/cx25840/cx25840-core.c
++++ b/drivers/media/i2c/cx25840/cx25840-core.c
+@@ -668,14 +668,14 @@ static void cx23885_initialize(struct i2c_client *client)
+ */
+ cx25840_write4(client, 0x404, 0x0010253e);
+
+- /* CC on - Undocumented Register */
++ /* CC on - VBI_LINE_CTRL3, FLD_VBI_MD_LINE12 */
+ cx25840_write(client, state->vbi_regs_offset + 0x42f, 0x66);
+
+ /* HVR-1250 / HVR1850 DIF related */
+ /* Power everything up */
+ cx25840_write4(client, 0x130, 0x0);
+
+- /* Undocumented */
++ /* SRC_COMB_CFG */
+ if (is_cx23888(state))
+ cx25840_write4(client, 0x454, 0x6628021F);
+ else
+@@ -1111,16 +1111,25 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
+ cx25840_write4(client, 0x410, 0xffff0dbf);
+ cx25840_write4(client, 0x414, 0x00137d03);
+
+- cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000);
+- cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b);
+- cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000);
+-
+- cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824);
+- cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc);
+- cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0);
+- cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000);
+- cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802);
+-
++ /* These are not VBI controls */
++ if (is_cx23888(state)) {
++ /* 888 MISC_TIM_CTRL */
++ cx25840_write4(client, 0x42c, 0x42600000);
++ /* 888 FIELD_COUNT */
++ cx25840_write4(client, 0x430, 0x0000039b);
++ /* 888 VSCALE_CTRL */
++ cx25840_write4(client, 0x438, 0x00000000);
++ /* 888 DFE_CTRL1 */
++ cx25840_write4(client, 0x440, 0xF8E3E824);
++ /* 888 DFE_CTRL2 */
++ cx25840_write4(client, 0x444, 0x401040dc);
++ /* 888 DFE_CTRL3 */
++ cx25840_write4(client, 0x448, 0xcd3f02a0);
++ /* 888 PLL_CTRL */
++ cx25840_write4(client, 0x44c, 0x161f1000);
++ /* 888 HTL_CTRL */
++ cx25840_write4(client, 0x450, 0x00000802);
++ }
+ cx25840_write4(client, 0x91c, 0x01000000);
+ cx25840_write4(client, 0x8e0, 0x03063870);
+ cx25840_write4(client, 0x8d4, 0x7FFF0024);
+@@ -1398,8 +1407,9 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
+ if ((fmt->width == 0) || (Vlines == 0) ||
+ (fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) {
+- v4l_err(client, "%dx%d is not a valid size!\n",
+- fmt->width, fmt->height);
++ v4l_err(client, "%dx%d is not a valid size! (Hsrc=%d, Vsrc=%d, Vlines=%d, is_50Hz=%u)\n",
++ fmt->width, fmt->height, Hsrc, Vsrc,
++ Vlines, is_50Hz);
+ return -ERANGE;
+ }
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY)
+@@ -1727,6 +1737,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
+ if (is_cx2388x(state) || is_cx231xx(state))
+ return 0;
+
++ /* PIN_CTRL1 */
+ if (enable) {
+ v = cx25840_read(client, 0x115) | 0x0c;
+ cx25840_write(client, 0x115, v);
+diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
+index 28eab9c..9b6c1f1 100644
+--- a/drivers/media/pci/cx23885/cx23885-cards.c
++++ b/drivers/media/pci/cx23885/cx23885-cards.c
+@@ -325,8 +325,7 @@ struct cx23885_board cx23885_boards[] = {
+ .name = "Hauppauge WinTV-HVR1255",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+- .tuner_type = TUNER_ABSENT,
+- .tuner_addr = 0x42, /* 0x84 >> 1 */
++ .tuner_type = TUNER_NXP_TDA18271,
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+@@ -354,8 +353,7 @@ struct cx23885_board cx23885_boards[] = {
+ .name = "Hauppauge WinTV-HVR1255",
+ .porta = CX23885_ANALOG_VIDEO,
+ .portc = CX23885_MPEG_DVB,
+- .tuner_type = TUNER_ABSENT,
+- .tuner_addr = 0x42, /* 0x84 >> 1 */
++ .tuner_type = TUNER_NXP_TDA18271,
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+@@ -767,14 +765,80 @@ struct cx23885_board cx23885_boards[] = {
+ } },
+ },
+ [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB] = {
+- .name = "Hauppauge WinTV-QuadHD-DVB",
++ .name = "Hauppauge WinTV-QuadHD-DVB",
++ .porta = CX23885_ANALOG_VIDEO,
++ .portb = CX23885_MPEG_DVB,
++ .portc = CX23885_MPEG_DVB,
++ .tuner_type = TUNER_ABSENT,
++ .force_bff = 1,
++ .input = {{
++ .type = CX23885_VMUX_TELEVISION,
++ .vmux = CX25840_VIN7_CH3 |
++ CX25840_VIN5_CH2 |
++ CX25840_VIN2_CH1 |
++ CX25840_DIF_ON,
++ .amux = CX25840_AUDIO8,
++ } },
++ },
++ [CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885] = {
++ .name = "Hauppauge WinTV-QuadHD-DVB(885)",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
++ .tuner_type = TUNER_ABSENT,
+ },
+ [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC] = {
+- .name = "Hauppauge WinTV-QuadHD-ATSC",
++ .name = "Hauppauge WinTV-QuadHD-ATSC",
++ .porta = CX23885_ANALOG_VIDEO,
++ .portb = CX23885_MPEG_DVB,
++ .portc = CX23885_MPEG_DVB,
++ .tuner_type = TUNER_ABSENT,
++ .force_bff = 1,
++ .input = {{
++ .type = CX23885_VMUX_TELEVISION,
++ .vmux = CX25840_VIN7_CH3 |
++ CX25840_VIN5_CH2 |
++ CX25840_VIN2_CH1 |
++ CX25840_DIF_ON,
++ .amux = CX25840_AUDIO8,
++ } },
++ },
++ [CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885] = {
++ .name = "Hauppauge WinTV-QuadHD-ATSC(885)",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
++ .tuner_type = TUNER_ABSENT,
++ },
++ [CX23885_BOARD_HAUPPAUGE_HVR1265_K4] = {
++ .name = "Hauppauge WinTV-HVR-1265(161111)",
++ .porta = CX23885_ANALOG_VIDEO,
++ .portc = CX23885_MPEG_DVB,
++ .tuner_type = TUNER_SILABS_SI2157,
++ .force_bff = 1,
++ .input = {{
++ .type = CX23885_VMUX_TELEVISION,
++ .vmux = CX25840_VIN7_CH3 |
++ CX25840_VIN5_CH2 |
++ CX25840_VIN2_CH1 |
++ CX25840_DIF_ON,
++ .amux = CX25840_AUDIO8,
++ }, {
++ .type = CX23885_VMUX_COMPOSITE1,
++ .vmux = CX25840_VIN7_CH3 |
++ CX25840_VIN4_CH2 |
++ CX25840_VIN6_CH1,
++ .amux = CX25840_AUDIO7,
++ }, {
++ .type = CX23885_VMUX_SVIDEO,
++ .vmux = CX25840_VIN7_CH3 |
++ CX25840_VIN4_CH2 |
++ CX25840_VIN8_CH1 |
++ CX25840_SVIDEO_ON,
++ .amux = CX25840_AUDIO7,
++ } },
++ },
++ [CX23885_BOARD_HAUPPAUGE_STARBURST2] = {
++ .name = "Hauppauge WinTV-Starburst2",
++ .portb = CX23885_MPEG_DVB,
+ },
+ };
+ const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
+@@ -1027,6 +1091,10 @@ struct cx23885_subid cx23885_subids[] = {
+ .subvendor = 0x0070,
+ .subdevice = 0x7133,
+ .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE,
++ }, {
++ .subvendor = 0x0070,
++ .subdevice = 0x7137,
++ .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb98,
+@@ -1087,7 +1155,16 @@ struct cx23885_subid cx23885_subids[] = {
+ .subvendor = 0x0070,
+ .subdevice = 0x6b18,
+ .card = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC, /* Tuner Pair 2 */
++ }, {
++ .subvendor = 0x0070,
++ .subdevice = 0x2a18,
++ .card = CX23885_BOARD_HAUPPAUGE_HVR1265_K4, /* Hauppauge WinTV HVR-1265 (Model 161xx1, Hybrid ATSC/QAM-B) */
++ }, {
++ .subvendor = 0x0070,
++ .subdevice = 0xf02a,
++ .card = CX23885_BOARD_HAUPPAUGE_STARBURST2,
+ },
++
+ };
+ const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
+
+@@ -1287,25 +1364,28 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+ case 150329:
+ /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */
+ break;
+- case 166100:
++ case 161111:
++ /* WinTV-HVR-1265 (PCIe, Analog/ATSC/QAM-B) */
++ break;
++ case 166100: /* 888 version, hybrid */
++ case 166200: /* 885 version, DVB only */
+ /* WinTV-QuadHD (DVB) Tuner Pair 1 (PCIe, IR, half height,
+ DVB-T/T2/C, DVB-T/T2/C */
+ break;
+- case 166101:
++ case 166101: /* 888 version, hybrid */
++ case 166201: /* 885 version, DVB only */
+ /* WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height,
+ DVB-T/T2/C, DVB-T/T2/C */
+ break;
+- case 165100:
+- /*
+- * WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height,
+- * ATSC, ATSC
+- */
++ case 165100: /* 888 version, hybrid */
++ case 165200: /* 885 version, digital only */
++ /* WinTV-QuadHD (ATSC) Tuner Pair 1 (PCIe, IR, half height,
++ * ATSC/QAM-B, ATSC/QAM-B */
+ break;
+- case 165101:
+- /*
+- * WinTV-QuadHD (DVB) Tuner Pair 2 (PCIe, IR, half height,
+- * ATSC, ATSC
+- */
++ case 165101: /* 888 version, hybrid */
++ case 165201: /* 885 version, digital only */
++ /* WinTV-QuadHD (ATSC) Tuner Pair 2 (PCIe, IR, half height,
++ * ATSC/QAM-B, ATSC/QAM-B */
+ break;
+ default:
+ pr_warn("%s: warning: unknown hauppauge model #%d\n",
+@@ -1778,8 +1858,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
+ cx23885_gpio_set(dev, GPIO_2);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
+- case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
+- case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
++ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
+ /*
+ * HVR5525 GPIO Details:
+ * GPIO-00 IR_WIDE
+@@ -1809,6 +1888,22 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
+ * card does not have any GPIO's connected to subcomponents.
+ */
+ break;
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
++ /*
++ * GPIO-08 TER1_RESN
++ * GPIO-09 TER2_RESN
++ */
++ /* Put the parts into reset and back */
++ cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
++ cx23885_gpio_clear(dev, GPIO_8 | GPIO_9);
++ msleep(100);
++ cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
++ msleep(100);
++ break;
+ }
+ }
+
+@@ -2054,8 +2149,13 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+ case CX23885_BOARD_HAUPPAUGE_STARBURST:
+ case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
++ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
++
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0xc0);
+ break;
+@@ -2194,6 +2294,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
++ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
+ 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;
+@@ -2201,8 +2302,11 @@ 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_HAUPPAUGE_HVR1265_K4:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
+ ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+@@ -2259,6 +2363,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
+ case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ case CX23885_BOARD_HAUPPAUGE_HVR1270:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_MYGICA_X8506:
+diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
+index 8f63df1..8afddd6 100644
+--- a/drivers/media/pci/cx23885/cx23885-core.c
++++ b/drivers/media/pci/cx23885/cx23885-core.c
+@@ -869,6 +869,14 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
+ cx23885_card_list(dev);
+ }
+
++ if (dev->pci->device == 0x8852) {
++ /* no DIF on cx23885, so no analog tuner support possible */
++ if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC)
++ dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885;
++ else if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB)
++ dev->board = CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885;
++ }
++
+ /* If the user specific a clk freq override, apply it */
+ if (cx23885_boards[dev->board].clk_freq > 0)
+ dev->clk_freq = cx23885_boards[dev->board].clk_freq;
+diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
+index 67ad041..53e59e4 100644
+--- a/drivers/media/pci/cx23885/cx23885-dvb.c
++++ b/drivers/media/pci/cx23885/cx23885-dvb.c
+@@ -930,6 +930,18 @@ static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = {
+ .agc = 0x99,
+ };
+
++static struct lgdt3306a_config hauppauge_hvr1265k4_config = {
++ .i2c_addr = 0x59,
++ .qam_if_khz = 4000,
++ .vsb_if_khz = 3250,
++ .deny_i2c_rptr = 1, /* Disabled */
++ .spectral_inversion = 0, /* Disabled */
++ .mpeg_mode = LGDT3306A_MPEG_SERIAL,
++ .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE,
++ .tpvalid_polarity = LGDT3306A_TP_VALID_HIGH,
++ .xtalMHz = 25, /* 24 or 25 */
++};
++
+ static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
+ {
+ struct cx23885_dev *dev = (struct cx23885_dev *)device;
+@@ -2217,10 +2229,15 @@ static int dvb_register(struct cx23885_tsport *port)
+ }
+ port->i2c_client_tuner = client_tuner;
+ break;
+- case CX23885_BOARD_HAUPPAUGE_HVR5525: {
++ case CX23885_BOARD_HAUPPAUGE_STARBURST2:
++ case CX23885_BOARD_HAUPPAUGE_HVR5525:
++ i2c_bus = &dev->i2c_bus[0];
++ i2c_bus2 = &dev->i2c_bus[1];
++
+ struct m88rs6000t_config m88rs6000t_config;
+ struct a8293_platform_data a8293_pdata = {};
+
++ pr_info("%s(): port=%d\n", __func__, port->nr);
+ switch (port->nr) {
+
+ /* port b - satellite */
+@@ -2228,7 +2245,7 @@ static int dvb_register(struct cx23885_tsport *port)
+ /* attach frontend */
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+ &hauppauge_hvr5525_m88ds3103_config,
+- &dev->i2c_bus[0].i2c_adap, &adapter);
++ &i2c_bus->i2c_adap, &adapter);
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+@@ -2239,7 +2256,7 @@ static int dvb_register(struct cx23885_tsport *port)
+ info.addr = 0x0b;
+ info.platform_data = &a8293_pdata;
+ request_module("a8293");
+- client_sec = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info);
++ client_sec = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ if (!client_sec || !client_sec->dev.driver)
+ goto frontend_detach;
+ if (!try_module_get(client_sec->dev.driver->owner)) {
+@@ -2281,7 +2298,7 @@ static int dvb_register(struct cx23885_tsport *port)
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module("%s", info.type);
+- client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info);
++ client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ if (!client_demod || !client_demod->dev.driver)
+ goto frontend_detach;
+ if (!try_module_get(client_demod->dev.driver->owner)) {
+@@ -2299,7 +2316,7 @@ static int dvb_register(struct cx23885_tsport *port)
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module("%s", info.type);
+- client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info);
++ client_tuner = i2c_new_device(&i2c_bus2->i2c_adap, &info);
+ if (!client_tuner || !client_tuner->dev.driver) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+@@ -2317,8 +2334,10 @@ static int dvb_register(struct cx23885_tsport *port)
+ break;
+ }
+ break;
+- }
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885:
++ pr_info("%s(): board=%d port=%d\n", __func__,
++ dev->board, port->nr);
+ switch (port->nr) {
+ /* port b - Terrestrial/cable */
+ case 1:
+@@ -2365,6 +2384,16 @@ static int dvb_register(struct cx23885_tsport *port)
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
++
++ /* we only attach tuner for analog on the 888 version */
++ if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) {
++ pr_info("%s(): QUADHD_DVB analog setup\n",
++ __func__);
++ dev->ts1.analog_fe.tuner_priv = client_tuner;
++ dvb_attach(si2157_attach, &dev->ts1.analog_fe,
++ info.addr, &dev->i2c_bus[1].i2c_adap,
++ &si2157_config);
++ }
+ break;
+
+ /* port c - terrestrial/cable */
+@@ -2416,6 +2445,9 @@ static int dvb_register(struct cx23885_tsport *port)
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885:
++ pr_info("%s(): board=%d port=%d\n", __func__,
++ dev->board, port->nr);
+ switch (port->nr) {
+ /* port b - Terrestrial/cable */
+ case 1:
+@@ -2451,6 +2483,16 @@ static int dvb_register(struct cx23885_tsport *port)
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
++
++ /* we only attach tuner for analog on the 888 version */
++ if (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC) {
++ pr_info("%s(): QUADHD_ATSC analog setup\n",
++ __func__);
++ dev->ts1.analog_fe.tuner_priv = client_tuner;
++ dvb_attach(si2157_attach, &dev->ts1.analog_fe,
++ info.addr, &dev->i2c_bus[1].i2c_adap,
++ &si2157_config);
++ }
+ break;
+
+ /* port c - terrestrial/cable */
+@@ -2490,6 +2532,47 @@ static int dvb_register(struct cx23885_tsport *port)
+ break;
+ }
+ break;
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
++ pr_info("%s(): port=%d\n", __func__, port->nr);
++ switch (port->nr) {
++ /* port c - Terrestrial/cable */
++ case 2:
++ /* attach frontend */
++ i2c_bus = &dev->i2c_bus[0];
++ fe0->dvb.frontend = dvb_attach(lgdt3306a_attach,
++ &hauppauge_hvr1265k4_config, &i2c_bus->i2c_adap);
++ if (fe0->dvb.frontend == NULL)
++ break;
++
++ /* attach tuner */
++ si2157_config.fe = fe0->dvb.frontend;
++ si2157_config.if_port = 1;
++ si2157_config.inversion = 1;
++ 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("%s", info.type);
++ client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info);
++ if (!client_tuner || !client_tuner->dev.driver) {
++ goto frontend_detach;
++ }
++ if (!try_module_get(client_tuner->dev.driver->owner)) {
++ i2c_unregister_device(client_tuner);
++ client_tuner = NULL;
++ goto frontend_detach;
++ }
++ port->i2c_client_tuner = client_tuner;
++
++ dev->ts1.analog_fe.tuner_priv = client_tuner;
++ dvb_attach(si2157_attach, &dev->ts1.analog_fe,
++ 0x60, &dev->i2c_bus[1].i2c_adap,
++ &si2157_config);
++ pr_info("%s(): HVR1265_K4 setup\n", __func__);
++ break;
++ }
++ break;
++
+
+ default:
+ pr_info("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
+diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
+index 0f4e542..be49589 100644
+--- a/drivers/media/pci/cx23885/cx23885-input.c
++++ b/drivers/media/pci/cx23885/cx23885-input.c
+@@ -94,6 +94,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ /*
+ * The only boards we handle right now. However other boards
+ * using the CX2388x integrated IR controller should be similar
+@@ -153,6 +154,7 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ /*
+ * The IR controller on this board only returns pulse widths.
+ * Any other mode setting will fail to set up the device.
+@@ -283,6 +285,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
+ case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ /* Integrated CX2388[58] IR controller */
+ allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER;
+ /* The grey Hauppauge RC-5 remote */
+diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
+index ecc580a..afa383f 100644
+--- a/drivers/media/pci/cx23885/cx23885-video.c
++++ b/drivers/media/pci/cx23885/cx23885-video.c
+@@ -263,6 +263,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
+ (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
++ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) ||
++ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC) ||
++ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
+ (dev->board == CX23885_BOARD_MYGICA_X8507) ||
+ (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) ||
+@@ -993,7 +996,10 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
+
+ if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
+- (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111))
++ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
++ (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1265_K4) ||
++ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_DVB) ||
++ (dev->board == CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC))
+ fe = &dev->ts1.analog_fe;
+
+ if (fe && fe->ops.tuner_ops.set_analog_params) {
+@@ -1022,7 +1028,10 @@ int cx23885_set_frequency(struct file *file, void *priv,
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1255:
+ case CX23885_BOARD_HAUPPAUGE_HVR1255_22111:
++ case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
+ case CX23885_BOARD_HAUPPAUGE_HVR1850:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_DVB:
++ case CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC:
+ ret = cx23885_set_freq_via_ops(dev, f);
+ break;
+ default:
+diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
+index 6aab713..6e659be 100644
+--- a/drivers/media/pci/cx23885/cx23885.h
++++ b/drivers/media/pci/cx23885/cx23885.h
+@@ -107,6 +107,10 @@
+ #define CX23885_BOARD_VIEWCAST_460E 55
+ #define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB 56
+ #define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC 57
++#define CX23885_BOARD_HAUPPAUGE_HVR1265_K4 58
++#define CX23885_BOARD_HAUPPAUGE_STARBURST2 59
++#define CX23885_BOARD_HAUPPAUGE_QUADHD_DVB_885 60
++#define CX23885_BOARD_HAUPPAUGE_QUADHD_ATSC_885 61
+
+ #define GPIO_0 0x00000001
+ #define GPIO_1 0x00000002
+diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
+index e76d3ba..9522c6c 100644
+--- a/drivers/media/pci/saa7164/saa7164-dvb.c
++++ b/drivers/media/pci/saa7164/saa7164-dvb.c
+@@ -110,8 +110,9 @@ static struct si2157_config hauppauge_hvr2255_tuner_config = {
+ .if_port = 1,
+ };
+
+-static int si2157_attach(struct saa7164_port *port, struct i2c_adapter *adapter,
+- struct dvb_frontend *fe, u8 addr8bit, struct si2157_config *cfg)
++static int si2157_attach_priv(struct saa7164_port *port,
++ struct i2c_adapter *adapter, struct dvb_frontend *fe,
++ u8 addr8bit, struct si2157_config *cfg)
+ {
+ struct i2c_board_info bi;
+ struct i2c_client *tuner;
+@@ -624,11 +625,13 @@ int saa7164_dvb_register(struct saa7164_port *port)
+ if (port->dvb.frontend != NULL) {
+
+ if (port->nr == 0) {
+- si2157_attach(port, &dev->i2c_bus[0].i2c_adap,
++ si2157_attach_priv(port,
++ &dev->i2c_bus[0].i2c_adap,
+ port->dvb.frontend, 0xc0,
+ &hauppauge_hvr2255_tuner_config);
+ } else {
+- si2157_attach(port, &dev->i2c_bus[1].i2c_adap,
++ si2157_attach_priv(port,
++ &dev->i2c_bus[1].i2c_adap,
+ port->dvb.frontend, 0xc0,
+ &hauppauge_hvr2255_tuner_config);
+ }
+diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
+index e35b1fa..2f79bdb 100644
+--- a/drivers/media/tuners/si2157.c
++++ b/drivers/media/tuners/si2157.c
+@@ -1,5 +1,5 @@
+ /*
+- * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
++ * Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver
+ *
+ * Copyright (C) 2014 Antti Palosaari
+ *
+@@ -18,6 +18,11 @@
+
+ static const struct dvb_tuner_ops si2157_ops;
+
++static DEFINE_MUTEX(si2157_list_mutex);
++static LIST_HEAD(hybrid_tuner_instance_list);
++
++/*---------------------------------------------------------------------*/
++
+ /* execute firmware command */
+ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
+ {
+@@ -52,18 +57,25 @@ static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
+ }
+
+ /* firmware ready? */
+- if ((cmd->args[0] >> 7) & 0x01)
++ if (cmd->args[0] & 0x80)
+ break;
++ usleep_range(5000, 10000);
+ }
+
+- dev_dbg(&client->dev, "cmd execution took %d ms\n",
++ dev_dbg(&client->dev, "cmd execution took %d ms, status=%x\n",
+ jiffies_to_msecs(jiffies) -
+- (jiffies_to_msecs(timeout) - TIMEOUT));
++ (jiffies_to_msecs(timeout) - TIMEOUT),
++ cmd->args[0]);
+
+- if (!((cmd->args[0] >> 7) & 0x01)) {
++ if (!(cmd->args[0] & 0x80)) {
+ ret = -ETIMEDOUT;
+ goto err_mutex_unlock;
+ }
++ /* check error status bit */
++ if (cmd->args[0] & 0x40) {
++ ret = -EAGAIN;
++ goto err_mutex_unlock;
++ }
+ }
+
+ mutex_unlock(&dev->i2c_mutex);
+@@ -84,24 +96,25 @@ static int si2157_init(struct dvb_frontend *fe)
+ struct si2157_cmd cmd;
+ const struct firmware *fw;
+ const char *fw_name;
+- unsigned int uitmp, chip_id;
++ unsigned int chip_id, xtal_trim;
+
+ dev_dbg(&client->dev, "\n");
+
+- /* Returned IF frequency is garbage when firmware is not running */
+- memcpy(cmd.args, "\x15\x00\x06\x07", 4);
++ /* Try to get Xtal trim property setting, to verify tuner still running;
++ * replaces previous test of IF freq
++ */
++ memcpy(cmd.args, "\x15\x00\x04\x02", 4);
+ cmd.wlen = 4;
+ cmd.rlen = 4;
+ ret = si2157_cmd_execute(client, &cmd);
+- if (ret)
+- goto err;
+
+- uitmp = cmd.args[2] << 0 | cmd.args[3] << 8;
+- dev_dbg(&client->dev, "if_frequency kHz=%u\n", uitmp);
++ xtal_trim = cmd.args[2] | (cmd.args[3] << 8);
+
+- if (uitmp == dev->if_frequency / 1000)
++ if ((ret == 0) && (xtal_trim < 16))
+ goto warm;
+
++ dev->if_frequency = 0; /* we no longer know current tuner state */
++
+ /* power up */
+ if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
+ memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
+@@ -230,6 +243,45 @@ skip_fw_download:
+
+ dev_info(&client->dev, "firmware version: %c.%c.%d\n",
+ cmd.args[6], cmd.args[7], cmd.args[8]);
++
++ if (dev->chiptype == SI2157_CHIPTYPE_SI2141) {
++ /* set clock */
++ memcpy(cmd.args, "\xc0\x00\x0d", 3);
++ cmd.wlen = 3;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++ /* setup PIN */
++ memcpy(cmd.args, "\x12\x80\x80\x85\x00\x81\x00", 7);
++ cmd.wlen = 7;
++ cmd.rlen = 7;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++ }
++
++ /* enable tuner status flags, for si2157_tune_wait() */
++ memcpy(cmd.args, "\x14\x00\x01\x05\x01\x00", 6);
++ cmd.wlen = 6;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ memcpy(cmd.args, "\x14\x00\x01\x06\x01\x00", 6);
++ cmd.wlen = 6;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ memcpy(cmd.args, "\x14\x00\x01\x07\x01\x00", 6);
++ cmd.wlen = 6;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
+ warm:
+ /* init statistics in order signal app which are supported */
+ c->strength.len = 1;
+@@ -250,7 +302,7 @@ static int si2157_sleep(struct dvb_frontend *fe)
+ {
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+- int ret;
++ int ret = 0;
+ struct si2157_cmd cmd;
+
+ dev_dbg(&client->dev, "\n");
+@@ -274,6 +326,84 @@ err:
+ return ret;
+ }
+
++static int si2157_tune_wait(struct i2c_client *client, u8 is_digital)
++{
++#define TUN_TIMEOUT 40
++#define DIG_TIMEOUT 30
++#define ANALOG_TIMEOUT 150
++ struct si2157_dev *dev = i2c_get_clientdata(client);
++ int ret;
++ unsigned long timeout;
++ unsigned long start_time;
++ u8 wait_status;
++ u8 tune_lock_mask;
++
++ if (is_digital)
++ tune_lock_mask = 0x04;
++ else
++ tune_lock_mask = 0x02;
++
++ mutex_lock(&dev->i2c_mutex);
++
++ /* wait tuner command complete */
++ start_time = jiffies;
++ timeout = start_time + msecs_to_jiffies(TUN_TIMEOUT);
++ while (!time_after(jiffies, timeout)) {
++ ret = i2c_master_recv(client, &wait_status,
++ sizeof(wait_status));
++ if (ret < 0) {
++ goto err_mutex_unlock;
++ } else if (ret != sizeof(wait_status)) {
++ ret = -EREMOTEIO;
++ goto err_mutex_unlock;
++ }
++
++ /* tuner done? */
++ if ((wait_status & 0x81) == 0x81)
++ break;
++ usleep_range(5000, 10000);
++ }
++ /* if we tuned ok, wait a bit for tuner lock */
++ if ((wait_status & 0x81) == 0x81) {
++ if (is_digital)
++ timeout = jiffies + msecs_to_jiffies(DIG_TIMEOUT);
++ else
++ timeout = jiffies + msecs_to_jiffies(ANALOG_TIMEOUT);
++ while (!time_after(jiffies, timeout)) {
++ ret = i2c_master_recv(client, &wait_status,
++ sizeof(wait_status));
++ if (ret < 0) {
++ goto err_mutex_unlock;
++ } else if (ret != sizeof(wait_status)) {
++ ret = -EREMOTEIO;
++ goto err_mutex_unlock;
++ }
++
++ /* tuner locked? */
++ if (wait_status & tune_lock_mask)
++ break;
++ usleep_range(5000, 10000);
++ }
++ }
++
++ dev_dbg(&client->dev, "tuning took %d ms, status=0x%x\n",
++ jiffies_to_msecs(jiffies) - jiffies_to_msecs(start_time),
++ wait_status);
++
++ if ((wait_status & 0xc0) != 0x80) {
++ ret = -ETIMEDOUT;
++ goto err_mutex_unlock;
++ }
++
++ mutex_unlock(&dev->i2c_mutex);
++ return 0;
++
++err_mutex_unlock:
++ mutex_unlock(&dev->i2c_mutex);
++ dev_dbg(&client->dev, "failed=%d\n", ret);
++ return ret;
++}
++
+ static int si2157_set_params(struct dvb_frontend *fe)
+ {
+ struct i2c_client *client = fe->tuner_priv;
+@@ -344,7 +474,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
+ if (ret)
+ goto err;
+
+- /* set if frequency if needed */
++ /* set digital if frequency if needed */
+ if (if_frequency != dev->if_frequency) {
+ memcpy(cmd.args, "\x14\x00\x06\x07", 4);
+ cmd.args[4] = (if_frequency / 1000) & 0xff;
+@@ -358,7 +488,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
+ dev->if_frequency = if_frequency;
+ }
+
+- /* set frequency */
++ /* set digital frequency */
+ memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
+ cmd.args[4] = (c->frequency >> 0) & 0xff;
+ cmd.args[5] = (c->frequency >> 8) & 0xff;
+@@ -370,24 +500,319 @@ static int si2157_set_params(struct dvb_frontend *fe)
+ if (ret)
+ goto err;
+
++ /* wait for tuning to complete, ignore any errors */
++ si2157_tune_wait(client, 1);
++
++ dev->bandwidth = bandwidth;
++ dev->frequency = c->frequency;
++
++ return 0;
++err:
++ dev->bandwidth = 0;
++ dev->frequency = 0;
++ dev->if_frequency = 0;
++ dev_dbg(&client->dev, "failed=%d\n", ret);
++ return ret;
++}
++
++static int si2157_set_analog_params(struct dvb_frontend *fe,
++ struct analog_parameters *params)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct si2157_dev *dev = i2c_get_clientdata(client);
++ char *std; /* for debugging */
++ int ret;
++ struct si2157_cmd cmd;
++ u32 bandwidth = 0;
++ u32 if_frequency = 0;
++ u32 freq = 0;
++ u64 tmp_lval = 0;
++ u8 system = 0;
++ u8 color = 0; /* 0=NTSC/PAL, 0x10=SECAM */
++ u8 invert_analog = 1; /* analog tuner spectrum; 0=normal, 1=inverted */
++
++ if (dev->chiptype != SI2157_CHIPTYPE_SI2157) {
++ dev_info(&client->dev, "%s: Analog tuning not supported for chiptype=%u\n",
++ __func__, dev->chiptype);
++ ret = -EINVAL;
++ goto err;
++ }
++
++ if (!dev->active)
++ si2157_init(fe);
++
++ if (!dev->active) {
++ ret = -EAGAIN;
++ goto err;
++ }
++ if (params->mode == V4L2_TUNER_RADIO) {
++ /*
++ * std = "fm";
++ * bandwidth = 1700000; //best can do for FM, AGC will be a mess though
++ * if_frequency = 1250000; //HVR-225x(saa7164), HVR-12xx(cx23885)
++ * if_frequency = 6600000; //HVR-9xx(cx231xx)
++ * if_frequency = 5500000; //HVR-19xx(pvrusb2)
++ */
++ dev_dbg(&client->dev, "si2157 does not currently support FM radio\n");
++ ret = -EINVAL;
++ goto err;
++ }
++ tmp_lval = params->frequency * 625LL;
++ do_div(tmp_lval, 10); /* convert to HZ */
++ freq = (u32)tmp_lval;
++
++ if (freq < 1000000) /* is freq in KHz */
++ freq = freq * 1000;
++ dev->frequency = freq;
++
++ if (params->std & (V4L2_STD_B|V4L2_STD_GH)) {
++ if (freq >= 470000000) {
++ std = "palGH";
++ bandwidth = 8000000;
++ if_frequency = 6000000; /* matches tda18271C2, works w/cx23885 */
++ system = 1;
++ if (params->std & (V4L2_STD_SECAM_G|V4L2_STD_SECAM_H)) {
++ std = "secamGH";
++ color = 0x10;
++ }
++ } else {
++ std = "palB";
++ bandwidth = 7000000;
++ if_frequency = 6000000; /* matches tda18271C2, works w/cx23885 */;
++ system = 0;
++ if (params->std & V4L2_STD_SECAM_B) {
++ std = "secamB";
++ color = 0x10;
++ }
++ }
++ } else if (params->std & V4L2_STD_MN) {
++ std = "MN";
++ bandwidth = 6000000;
++ if_frequency = 5400000; /* matches tda18271C2, works w/cx23885 */
++ system = 2;
++ } else if (params->std & V4L2_STD_PAL_I) {
++ std = "palI";
++ bandwidth = 8000000;
++ if_frequency = 7250000; /* matches tda18271C2, does not work yet w/cx23885 */
++ system = 4;
++ } else if (params->std & V4L2_STD_DK) {
++ std = "palDK";
++ bandwidth = 8000000;
++ if_frequency = 6900000; /* matches tda18271C2, does not work yet w/cx23885 */
++ system = 5;
++ if (params->std & V4L2_STD_SECAM_DK) {
++ std = "secamDK";
++ color = 0x10;
++ }
++ } else if (params->std & V4L2_STD_SECAM_L) {
++ std = "secamL";
++ bandwidth = 8000000;
++ if_frequency = 6750000; /* not tested yet w/cx23885 */
++ system = 6; color = 0x10;
++ } else if (params->std & V4L2_STD_SECAM_LC) {
++ std = "secamL'";
++ bandwidth = 7000000;
++ if_frequency = 1250000; /* not tested yet w/cx23885 */
++ system = 7; color = 0x10;
++ } else {
++ std = "unknown";
++ }
++ /* calc channel center freq */
++ freq = freq - 1250000 + (bandwidth/2);
++
++ dev_dbg(&client->dev,
++ "mode=%d system=%u std='%s' params->frequency=%u center freq=%u if=%u bandwidth=%u\n",
++ params->mode, system, std, params->frequency,
++ freq, if_frequency, bandwidth);
++
++ /* set analog IF port */
++ memcpy(cmd.args, "\x14\x00\x03\x06\x08\x02", 6);
++ /* in using dev->if_port, we assume analog and digital IF's */
++ /* are always on different ports */
++ /* assumes if_port definition is 0 or 1 for digital out */
++ cmd.args[4] = (dev->if_port == 1)?8:10;
++ cmd.args[5] = (dev->if_port == 1)?2:1; /* Analog AGC assumed external */
++ cmd.wlen = 6;
++ cmd.rlen = 4;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ /* set analog IF output config */
++ memcpy(cmd.args, "\x14\x00\x0d\x06\x94\x64", 6);
++ cmd.wlen = 6;
++ cmd.rlen = 4;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ /* make this distinct from a digital IF */
++ dev->if_frequency = if_frequency | 1;
++
++ /* calc and set tuner analog if center frequency */
++ if_frequency = if_frequency + 1250000 - (bandwidth/2);
++ dev_dbg(&client->dev, "IF Ctr freq=%d\n", if_frequency);
++
++ memcpy(cmd.args, "\x14\x00\x0C\x06", 4);
++ cmd.args[4] = (if_frequency / 1000) & 0xff;
++ cmd.args[5] = ((if_frequency / 1000) >> 8) & 0xff;
++ cmd.wlen = 6;
++ cmd.rlen = 4;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ /* set analog AGC config */
++ memcpy(cmd.args, "\x14\x00\x07\x06\x32\xc8", 6);
++ cmd.wlen = 6;
++ cmd.rlen = 4;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ /* set analog video mode */
++ memcpy(cmd.args, "\x14\x00\x04\x06\x00\x00", 6);
++ cmd.args[4] = system | color;
++#if 1 /* can use dev->inversion if assumed it applies to both digital/analog */
++ if (invert_analog)
++ cmd.args[5] |= 0x02;
++#else
++ if (dev->inversion)
++ cmd.args[5] |= 0x02;
++#endif
++ cmd.wlen = 6;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ /* set analog frequency */
++ memcpy(cmd.args, "\x41\x01\x00\x00\x00\x00\x00\x00", 8);
++ cmd.args[4] = (freq >> 0) & 0xff;
++ cmd.args[5] = (freq >> 8) & 0xff;
++ cmd.args[6] = (freq >> 16) & 0xff;
++ cmd.args[7] = (freq >> 24) & 0xff;
++ cmd.wlen = 8;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ if (ret)
++ goto err;
++
++ /* wait for tuning to complete, ignore any errors */
++ si2157_tune_wait(client, 0);
++
++#if 1 /* testing */
++ /* get tuner status, RSSI values */
++ memcpy(cmd.args, "\x42\x01", 2);
++ cmd.wlen = 2;
++ cmd.rlen = 12;
++ ret = si2157_cmd_execute(client, &cmd);
++
++ dev_info(&client->dev, "%s: tuner status: ret=%d rssi=%d mode=%x freq=%d\n",
++ __func__, ret, cmd.args[3], cmd.args[8],
++ (cmd.args[7]<<24 | cmd.args[6]<<16 |
++ cmd.args[5]<<8 | cmd.args[4]));
++#endif
++
++ dev->bandwidth = bandwidth;
++
+ return 0;
+ err:
++ dev->bandwidth = 0;
++ dev->frequency = 0;
++ dev->if_frequency = 0;
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+ }
+
++static int si2157_get_frequency(struct dvb_frontend *fe, u32 *frequency)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct si2157_dev *dev = i2c_get_clientdata(client);
++
++ *frequency = dev->frequency;
++ dev_info(&client->dev, "%s: freq=%u\n", __func__, dev->frequency);
++ return 0;
++}
++
++static int si2157_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct si2157_dev *dev = i2c_get_clientdata(client);
++
++ *bandwidth = dev->bandwidth;
++ dev_info(&client->dev, "%s: bandwidth=%u\n", __func__, dev->bandwidth);
++ return 0;
++}
++
+ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+ {
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+
+- *frequency = dev->if_frequency;
++ *frequency = dev->if_frequency & ~1; /* strip analog IF indicator bit */
++ dev_info(&client->dev, "%s: if_frequency=%u\n", __func__, *frequency);
++ return 0;
++}
++
++static void si2157_release(struct dvb_frontend *fe)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct si2157_dev *dev = NULL;
++
++ pr_info("%s: client=%p\n", __func__, client);
++ if (client == NULL)
++ return;
++
++ dev = i2c_get_clientdata(client);
++ pr_info("%s: dev=%p\n", __func__, dev);
++ if (dev == NULL)
++ return;
++
++ /* only remove dev reference from final instance */
++ if (hybrid_tuner_report_instance_count(dev) == 1)
++ i2c_set_clientdata(client, NULL);
++
++ mutex_lock(&si2157_list_mutex);
++ hybrid_tuner_release_state(dev);
++ mutex_unlock(&si2157_list_mutex);
++
++ fe->tuner_priv = NULL;
++}
++
++static int si2157_setup_configuration(struct dvb_frontend *fe,
++ struct si2157_config *cfg)
++{
++ struct i2c_client *client = fe->tuner_priv;
++ struct si2157_dev *dev = NULL;
++
++ pr_info("%s: client=%p\n", __func__, client);
++ if (client == NULL)
++ return -1;
++
++ dev = i2c_get_clientdata(client);
++ pr_info("%s: dev=%p\n", __func__, dev);
++ if (dev == NULL)
++ return -1;
++
++ if (cfg) {
++ pr_info("%s(0x%02X): dvb driver submitted configuration; port=%d invert=%d\n",
++ __func__, dev->addr,
++ cfg->if_port, cfg->inversion);
++ dev->inversion = cfg->inversion;
++ dev->if_port = cfg->if_port;
++ } else {
++ pr_info("%s(0x%02X): default configuration\n",
++ __func__, dev->addr);
++ dev->inversion = true;
++ dev->if_port = 1;
++ }
+ return 0;
+ }
+
+ static const struct dvb_tuner_ops si2157_ops = {
+ .info = {
+- .name = "Silicon Labs Si2141/Si2146/2147/2148/2157/2158",
++ .name = "Silicon Labs Si2141/2146/2147/2148/2157/2158",
+ .frequency_min = 42000000,
+ .frequency_max = 870000000,
+ },
+@@ -395,6 +820,10 @@ static const struct dvb_tuner_ops si2157_ops = {
+ .init = si2157_init,
+ .sleep = si2157_sleep,
+ .set_params = si2157_set_params,
++ .set_analog_params = si2157_set_analog_params,
++ .release = si2157_release,
++ .get_frequency = si2157_get_frequency,
++ .get_bandwidth = si2157_get_bandwidth,
+ .get_if_frequency = si2157_get_if_frequency,
+ };
+
+@@ -417,7 +846,7 @@ static void si2157_stat_work(struct work_struct *work)
+ goto err;
+
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+- c->strength.stat[0].svalue = (s8) cmd.args[3] * 1000;
++ c->strength.stat[0].svalue = ((s8) cmd.args[3]) * 1000;
+
+ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+ return;
+@@ -431,60 +860,23 @@ static int si2157_probe(struct i2c_client *client,
+ {
+ struct si2157_config *cfg = client->dev.platform_data;
+ struct dvb_frontend *fe = cfg->fe;
+- struct si2157_dev *dev;
+- struct si2157_cmd cmd;
+- int ret;
++ struct si2157_dev *dev = NULL;
++ unsigned short addr = client->addr;
++ int ret = 0;
++
++ pr_info("%s: probing si2157 tuner fe=%p cfg=%p addr=0X%2x\n",
++ __func__, fe, cfg, addr);
++ fe->tuner_priv = client;
++ si2157_setup_configuration(fe, cfg);
+
+- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+- if (!dev) {
+- ret = -ENOMEM;
+- dev_err(&client->dev, "kzalloc() failed\n");
++ if (!dvb_attach(si2157_attach, fe, (u8)addr, client->adapter, cfg)) {
++ dev_err(&client->dev, "%s: attaching si2157 tuner failed\n",
++ __func__);
+ goto err;
+ }
+
+- i2c_set_clientdata(client, dev);
+- dev->fe = cfg->fe;
+- dev->inversion = cfg->inversion;
+- dev->if_port = cfg->if_port;
++ dev = i2c_get_clientdata(client);
+ dev->chiptype = (u8)id->driver_data;
+- dev->if_frequency = 5000000; /* default value of property 0x0706 */
+- mutex_init(&dev->i2c_mutex);
+- INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
+-
+- /* check if the tuner is there */
+- cmd.wlen = 0;
+- cmd.rlen = 1;
+- ret = si2157_cmd_execute(client, &cmd);
+- if (ret)
+- goto err_kfree;
+-
+- memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
+- fe->tuner_priv = client;
+-
+-#ifdef CONFIG_MEDIA_CONTROLLER
+- if (cfg->mdev) {
+- dev->mdev = cfg->mdev;
+-
+- dev->ent.name = KBUILD_MODNAME;
+- dev->ent.function = MEDIA_ENT_F_TUNER;
+-
+- dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
+- dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
+- dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+-
+- ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
+- &dev->pad[0]);
+-
+- if (ret)
+- goto err_kfree;
+-
+- ret = media_device_register_entity(cfg->mdev, &dev->ent);
+- if (ret) {
+- media_entity_cleanup(&dev->ent);
+- goto err_kfree;
+- }
+- }
+-#endif
+
+ dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
+ dev->chiptype == SI2157_CHIPTYPE_SI2141 ? "Si2141" :
+@@ -493,8 +885,6 @@ static int si2157_probe(struct i2c_client *client,
+
+ return 0;
+
+-err_kfree:
+- kfree(dev);
+ err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+@@ -503,7 +893,13 @@ err:
+ static int si2157_remove(struct i2c_client *client)
+ {
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+- struct dvb_frontend *fe = dev->fe;
++ struct dvb_frontend *fe = NULL;
++
++ if (dev == NULL) {
++ pr_info("dev is NULL\n");
++ return 0;
++ }
++ fe = dev->fe;
+
+ dev_dbg(&client->dev, "\n");
+
+@@ -516,8 +912,7 @@ static int si2157_remove(struct i2c_client *client)
+ #endif
+
+ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+- fe->tuner_priv = NULL;
+- kfree(dev);
++ si2157_release(fe);
+
+ return 0;
+ }
+@@ -542,7 +937,129 @@ static struct i2c_driver si2157_driver = {
+
+ module_i2c_driver(si2157_driver);
+
+-MODULE_DESCRIPTION("Silicon Labs Si2141/Si2146/2147/2148/2157/2158 silicon tuner driver");
++struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
++ struct i2c_adapter *i2c,
++ struct si2157_config *cfg)
++{
++ struct i2c_client *client = NULL;
++ struct si2157_dev *dev = NULL;
++ struct si2157_cmd cmd;
++ int instance = 0, ret;
++
++ pr_info("%s (%d-%04x)\n", __func__,
++ i2c ? i2c_adapter_id(i2c) : 0,
++ addr);
++
++ mutex_lock(&si2157_list_mutex);
++
++ if (!cfg) {
++ pr_info("no configuration submitted\n");
++ goto fail;
++ }
++
++ if (!fe) {
++ pr_info("fe is NULL\n");
++ goto fail;
++ }
++
++ client = fe->tuner_priv;
++ if (!client) {
++ pr_info("client is NULL\n");
++ goto fail;
++ }
++
++ instance = hybrid_tuner_request_state(struct si2157_dev, dev,
++ hybrid_tuner_instance_list,
++ i2c, addr, "si2157");
++
++ pr_info("%s: instance=%d\n", __func__, instance);
++ switch (instance) {
++ case 0:
++ goto fail;
++ case 1:
++ /* new tuner instance */
++ pr_info("%s(): new instance for tuner @0x%02x\n",
++ __func__, addr);
++ dev->addr = addr;
++ i2c_set_clientdata(client, dev);
++
++ si2157_setup_configuration(fe, cfg);
++
++ dev->fe = fe;
++ /* BUGBUG - should chiptype come from config? */
++ dev->chiptype = (u8)SI2157_CHIPTYPE_SI2157;
++ dev->if_frequency = 0;
++
++ mutex_init(&dev->i2c_mutex);
++ INIT_DELAYED_WORK(&dev->stat_work, si2157_stat_work);
++
++ break;
++ default:
++ /* existing tuner instance */
++ pr_info("%s(): using existing instance for tuner @0x%02x\n",
++ __func__, addr);
++
++ /* allow dvb driver to override configuration settings */
++ if (cfg)
++ si2157_setup_configuration(fe, cfg);
++
++ break;
++ }
++
++ /* check if the tuner is there */
++ cmd.wlen = 0;
++ cmd.rlen = 1;
++ ret = si2157_cmd_execute(client, &cmd);
++ /* verify no i2c error and CTS is set */
++ if (ret && (ret != -EAGAIN)) {
++ pr_info("no HW found ret=%d\n", ret);
++ goto fail;
++ }
++
++ memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
++
++#ifdef CONFIG_MEDIA_CONTROLLER
++ if (instance == 1 && cfg->mdev) {
++ pr_info("cfg->mdev=%p\n", cfg->mdev);
++ dev->mdev = cfg->mdev;
++
++ dev->ent.name = KBUILD_MODNAME;
++ dev->ent.function = MEDIA_ENT_F_TUNER;
++
++ dev->pad[TUNER_PAD_RF_INPUT].flags = MEDIA_PAD_FL_SINK;
++ dev->pad[TUNER_PAD_OUTPUT].flags = MEDIA_PAD_FL_SOURCE;
++ dev->pad[TUNER_PAD_AUD_OUT].flags = MEDIA_PAD_FL_SOURCE;
++
++ ret = media_entity_pads_init(&dev->ent, TUNER_NUM_PADS,
++ &dev->pad[0]);
++
++ if (ret)
++ goto fail;
++
++ ret = media_device_register_entity(cfg->mdev, &dev->ent);
++ if (ret) {
++ pr_info("media_device_regiser_entity returns %d\n", ret);
++ media_entity_cleanup(&dev->ent);
++ goto fail;
++ }
++ }
++#endif
++
++ mutex_unlock(&si2157_list_mutex);
++
++ return fe;
++
++fail:
++ pr_info("%s: Failed\n", __func__);
++ mutex_unlock(&si2157_list_mutex);
++
++ if (fe && (instance == 1))
++ si2157_release(fe);
++ return NULL;
++}
++EXPORT_SYMBOL(si2157_attach);
++
++MODULE_DESCRIPTION("Silicon Labs Si2141/2146/2147/2148/2157/2158 silicon tuner driver");
+ MODULE_AUTHOR("Antti Palosaari ");
+ MODULE_LICENSE("GPL");
+ MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
+diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
+index 76807f5..fd008cc 100644
+--- a/drivers/media/tuners/si2157.h
++++ b/drivers/media/tuners/si2157.h
+@@ -46,4 +46,18 @@ struct si2157_config {
+ u8 if_port;
+ };
+
++#if IS_REACHABLE(CONFIG_MEDIA_TUNER_SI2157)
++extern struct dvb_frontend *si2157_attach(struct dvb_frontend *fe, u8 addr,
++ struct i2c_adapter *i2c,
++ struct si2157_config *cfg);
++#else
++static inline struct dvb_frontend *si2157_attach(struct dvb_frontend *fe,
++ u8 addr,
++ struct i2c_adapter *i2c,
++ struct si2157_config *cfg)
++{
++ pr_err("%s: driver disabled by Kconfig\n", __func__);
++ return NULL;
++}
++#endif
+ #endif
+diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
+index e6436f7..b51259b 100644
+--- a/drivers/media/tuners/si2157_priv.h
++++ b/drivers/media/tuners/si2157_priv.h
+@@ -19,17 +19,24 @@
+
+ #include
+ #include
++#include "tuner-i2c.h"
+ #include "si2157.h"
+
+ /* state struct */
+ struct si2157_dev {
++ struct list_head hybrid_tuner_instance_list;
++ struct tuner_i2c_props i2c_props;
++
+ struct mutex i2c_mutex;
+ struct dvb_frontend *fe;
+ bool active;
+ bool inversion;
+ u8 chiptype;
++ u8 addr;
+ u8 if_port;
+ u32 if_frequency;
++ u32 bandwidth;
++ u32 frequency;
+ struct delayed_work stat_work;
+
+ #if defined(CONFIG_MEDIA_CONTROLLER)
+diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c
+index 98bc15a..e022ab8 100644
+--- a/drivers/media/tuners/tuner-types.c
++++ b/drivers/media/tuners/tuner-types.c
+@@ -1433,6 +1433,16 @@ static struct tuner_params tuner_sony_btf_pg463z_params[] = {
+ },
+ };
+
++/* ------------ TUNER_SILABS_SI2157 NTSC/PAL/Digital ------------ */
++
++static struct tuner_params tuner_silabs_si2157_params[] = {
++ {
++ .type = TUNER_PARAM_TYPE_DIGITAL,
++ .ranges = tuner_fm1236_mk3_ntsc_ranges,
++ .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
++ },
++};
++
+ /* --------------------------------------------------------------------- */
+
+ struct tunertype tuners[] = {
+@@ -1941,6 +1951,11 @@ struct tunertype tuners[] = {
+ .params = tuner_sony_btf_pg463z_params,
+ .count = ARRAY_SIZE(tuner_sony_btf_pg463z_params),
+ },
++ [TUNER_SILABS_SI2157] = {
++ .name = "Silicon Labs Si2157 terrestrial/cable multistandard",
++ .params = tuner_silabs_si2157_params,
++ .count = ARRAY_SIZE(tuner_silabs_si2157_params),
++ },
+ };
+ EXPORT_SYMBOL(tuners);
+
+diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
+index 99c8b1a..e85ec3c 100644
+--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
++++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
+@@ -922,6 +922,84 @@ struct cx231xx_board cx231xx_boards[] = {
+ .gpio = NULL,
+ } },
+ },
++ [CX231XX_BOARD_HAUPPAUGE_935C] = {
++ .name = "Hauppauge WinTV-HVR-935C",
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = 0x60,
++ .tuner_gpio = RDE250_XCV_TUNER,
++ .tuner_sif_gpio = 0x05,
++ .tuner_scl_gpio = 0x1a,
++ .tuner_sda_gpio = 0x1b,
++ .decoder = CX231XX_AVDECODER,
++ .output_mode = OUT_MODE_VIP11,
++ .demod_xfer_mode = 0,
++ .ctl_pin_status_mask = 0xFFFFFFC4,
++ .agc_analog_digital_select_gpio = 0x0c,
++ .gpio_pin_status_mask = 0x4001000,
++ .tuner_i2c_master = I2C_1_MUX_3,
++ .demod_i2c_master = I2C_1_MUX_3,
++ .has_dvb = 1,
++ .demod_addr = 0x64, /* 0xc8 >> 1 */
++ .norm = V4L2_STD_PAL,
++
++ .input = {{
++ .type = CX231XX_VMUX_TELEVISION,
++ .vmux = CX231XX_VIN_3_1,
++ .amux = CX231XX_AMUX_VIDEO,
++ .gpio = NULL,
++ }, {
++ .type = CX231XX_VMUX_COMPOSITE1,
++ .vmux = CX231XX_VIN_2_1,
++ .amux = CX231XX_AMUX_LINE_IN,
++ .gpio = NULL,
++ }, {
++ .type = CX231XX_VMUX_SVIDEO,
++ .vmux = CX231XX_VIN_1_1 |
++ (CX231XX_VIN_1_2 << 8) |
++ CX25840_SVIDEO_ON,
++ .amux = CX231XX_AMUX_LINE_IN,
++ .gpio = NULL,
++ } },
++ },
++ [CX231XX_BOARD_HAUPPAUGE_975] = {
++ .name = "Hauppauge WinTV-HVR-975",
++ .tuner_type = TUNER_ABSENT,
++ .tuner_addr = 0x60,
++ .tuner_gpio = RDE250_XCV_TUNER,
++ .tuner_sif_gpio = 0x05,
++ .tuner_scl_gpio = 0x1a,
++ .tuner_sda_gpio = 0x1b,
++ .decoder = CX231XX_AVDECODER,
++ .output_mode = OUT_MODE_VIP11,
++ .demod_xfer_mode = 0,
++ .ctl_pin_status_mask = 0xFFFFFFC4,
++ .agc_analog_digital_select_gpio = 0x0c,
++ .gpio_pin_status_mask = 0x4001000,
++ .tuner_i2c_master = I2C_1_MUX_3,
++ .demod_i2c_master = I2C_1_MUX_3,
++ .has_dvb = 1,
++ .demod_addr = 0x64, /* 0xc8 >> 1 */
++ .norm = V4L2_STD_ALL,
++
++ .input = {{
++ .type = CX231XX_VMUX_TELEVISION,
++ .vmux = CX231XX_VIN_3_1,
++ .amux = CX231XX_AMUX_VIDEO,
++ .gpio = NULL,
++ }, {
++ .type = CX231XX_VMUX_COMPOSITE1,
++ .vmux = CX231XX_VIN_2_1,
++ .amux = CX231XX_AMUX_LINE_IN,
++ .gpio = NULL,
++ }, {
++ .type = CX231XX_VMUX_SVIDEO,
++ .vmux = CX231XX_VIN_1_1 |
++ (CX231XX_VIN_1_2 << 8) |
++ CX25840_SVIDEO_ON,
++ .amux = CX231XX_AMUX_LINE_IN,
++ .gpio = NULL,
++ } },
++ },
+ };
+ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
+
+@@ -953,6 +1031,10 @@ struct usb_device_id cx231xx_id_table[] = {
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+ {USB_DEVICE(0x2040, 0xb123),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q},
++ {USB_DEVICE(0x2040, 0xb151),
++ .driver_info = CX231XX_BOARD_HAUPPAUGE_935C},
++ {USB_DEVICE(0x2040, 0xb150),
++ .driver_info = CX231XX_BOARD_HAUPPAUGE_975},
+ {USB_DEVICE(0x2040, 0xb130),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
+ {USB_DEVICE(0x2040, 0xb131),
+diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
+index fb56540..20af416 100644
+--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
++++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
+@@ -55,7 +55,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+ #define CX231XX_DVB_MAX_PACKETS 64
+
+ struct cx231xx_dvb {
+- struct dvb_frontend *frontend;
++ struct dvb_frontend *frontend[2];
+
+ /* feed count management */
+ struct mutex lock;
+@@ -386,17 +386,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
+ cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
+ cfg.i2c_addr = addr;
+
+- if (!dev->dvb->frontend) {
++ if (!dev->dvb->frontend[0]) {
+ dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+- fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
++ fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg);
+ if (!fe) {
+ dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
+- dvb_frontend_detach(dev->dvb->frontend);
+- dev->dvb->frontend = NULL;
++ dvb_frontend_detach(dev->dvb->frontend[0]);
++ dev->dvb->frontend[0] = NULL;
+ return -EINVAL;
+ }
+
+@@ -408,9 +408,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
+
+ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
+ {
+- if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
++ if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
+
+- struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
++ struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
+
+ if (dops->set_analog_params != NULL) {
+ struct analog_parameters params;
+@@ -421,7 +421,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
+ /*params.audmode = ; */
+
+ /* Set the analog parameters to set the frequency */
+- dops->set_analog_params(dev->dvb->frontend, ¶ms);
++ dops->set_analog_params(dev->dvb->frontend[0], ¶ms);
+ }
+
+ }
+@@ -433,15 +433,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
+ {
+ int status = 0;
+
+- if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) {
++ if ((dev->dvb != NULL) && (dev->dvb->frontend[0] != NULL)) {
+
+- struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops;
++ struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops;
+
+ if (dops->init != NULL && !dev->xc_fw_load_done) {
+
+ dev_dbg(dev->dev,
+ "Reloading firmware for XC5000\n");
+- status = dops->init(dev->dvb->frontend);
++ status = dops->init(dev->dvb->frontend[0]);
+ if (status == 0) {
+ dev->xc_fw_load_done = 1;
+ dev_dbg(dev->dev,
+@@ -481,19 +481,32 @@ static int register_dvb(struct cx231xx_dvb *dvb,
+ dvb_register_media_controller(&dvb->adapter, dev->media_dev);
+
+ /* Ensure all frontends negotiate bus access */
+- dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
++ dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
++ if (dvb->frontend[1])
++ dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl;
+
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+- result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
++ result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]);
+ if (result < 0) {
+ dev_warn(dev->dev,
+ "%s: dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+- goto fail_frontend;
++ goto fail_frontend0;
+ }
+
++ if (dvb->frontend[1]) {
++ result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]);
++ if (result < 0) {
++ dev_warn(dev->dev,
++ "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
++ dev->name, result);
++ goto fail_frontend1;
++ }
++ }
++
++
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+@@ -569,9 +582,14 @@ fail_fe_hw:
+ fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+ fail_dmx:
+- dvb_unregister_frontend(dvb->frontend);
+-fail_frontend:
+- dvb_frontend_detach(dvb->frontend);
++ if (dvb->frontend[1])
++ dvb_unregister_frontend(dvb->frontend[1]);
++ dvb_unregister_frontend(dvb->frontend[0]);
++fail_frontend1:
++ if (dvb->frontend[1])
++ dvb_frontend_detach(dvb->frontend[1]);
++fail_frontend0:
++ dvb_frontend_detach(dvb->frontend[0]);
+ dvb_unregister_adapter(&dvb->adapter);
+ fail_adapter:
+ return result;
+@@ -585,8 +603,12 @@ static void unregister_dvb(struct cx231xx_dvb *dvb)
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+- dvb_unregister_frontend(dvb->frontend);
+- dvb_frontend_detach(dvb->frontend);
++ if (dvb->frontend[1])
++ dvb_unregister_frontend(dvb->frontend[1]);
++ dvb_unregister_frontend(dvb->frontend[0]);
++ if (dvb->frontend[1])
++ dvb_frontend_detach(dvb->frontend[1]);
++ dvb_frontend_detach(dvb->frontend[0]);
+ dvb_unregister_adapter(&dvb->adapter);
+ /* remove I2C tuner */
+ client = dvb->i2c_client_tuner;
+@@ -635,11 +657,11 @@ static int dvb_init(struct cx231xx *dev)
+ case CX231XX_BOARD_CNXT_CARRAERA:
+ case CX231XX_BOARD_CNXT_RDE_250:
+
+- dev->dvb->frontend = dvb_attach(s5h1432_attach,
++ dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
+ &dvico_s5h1432_config,
+ demod_i2c);
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach s5h1432 front end\n");
+ result = -EINVAL;
+@@ -647,9 +669,9 @@ static int dvb_init(struct cx231xx *dev)
+ }
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
++ if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
+ tuner_i2c,
+ &cnxt_rde250_tunerconfig)) {
+ result = -EINVAL;
+@@ -660,11 +682,11 @@ static int dvb_init(struct cx231xx *dev)
+ case CX231XX_BOARD_CNXT_SHELBY:
+ case CX231XX_BOARD_CNXT_RDU_250:
+
+- dev->dvb->frontend = dvb_attach(s5h1411_attach,
++ dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
+ &xc5000_s5h1411_config,
+ demod_i2c);
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach s5h1411 front end\n");
+ result = -EINVAL;
+@@ -672,9 +694,9 @@ static int dvb_init(struct cx231xx *dev)
+ }
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
++ if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
+ tuner_i2c,
+ &cnxt_rdu250_tunerconfig)) {
+ result = -EINVAL;
+@@ -683,11 +705,11 @@ static int dvb_init(struct cx231xx *dev)
+ break;
+ case CX231XX_BOARD_CNXT_RDE_253S:
+
+- dev->dvb->frontend = dvb_attach(s5h1432_attach,
++ dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
+ &dvico_s5h1432_config,
+ demod_i2c);
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach s5h1432 front end\n");
+ result = -EINVAL;
+@@ -695,9 +717,9 @@ static int dvb_init(struct cx231xx *dev)
+ }
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
++ if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
+ 0x60, tuner_i2c,
+ &cnxt_rde253s_tunerconfig)) {
+ result = -EINVAL;
+@@ -707,11 +729,11 @@ static int dvb_init(struct cx231xx *dev)
+ case CX231XX_BOARD_CNXT_RDU_253S:
+ case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:
+
+- dev->dvb->frontend = dvb_attach(s5h1411_attach,
++ dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
+ &tda18271_s5h1411_config,
+ demod_i2c);
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach s5h1411 front end\n");
+ result = -EINVAL;
+@@ -719,9 +741,9 @@ static int dvb_init(struct cx231xx *dev)
+ }
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
++ if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
+ 0x60, tuner_i2c,
+ &cnxt_rde253s_tunerconfig)) {
+ result = -EINVAL;
+@@ -734,11 +756,11 @@ static int dvb_init(struct cx231xx *dev)
+ "%s: looking for tuner / demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(tuner_i2c));
+
+- dev->dvb->frontend = dvb_attach(lgdt3305_attach,
++ dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
+ &hcw_lgdt3305_config,
+ demod_i2c);
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach LG3305 front end\n");
+ result = -EINVAL;
+@@ -746,9 +768,9 @@ static int dvb_init(struct cx231xx *dev)
+ }
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- dvb_attach(tda18271_attach, dev->dvb->frontend,
++ dvb_attach(tda18271_attach, dev->dvb->frontend[0],
+ 0x60, tuner_i2c,
+ &hcw_tda18271_config);
+ break;
+@@ -761,7 +783,7 @@ static int dvb_init(struct cx231xx *dev)
+
+ /* attach demod */
+ memset(&si2165_pdata, 0, sizeof(si2165_pdata));
+- si2165_pdata.fe = &dev->dvb->frontend;
++ si2165_pdata.fe = &dev->dvb->frontend[0];
+ si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL;
+ si2165_pdata.ref_freq_hz = 16000000;
+
+@@ -771,7 +793,7 @@ static int dvb_init(struct cx231xx *dev)
+ info.platform_data = &si2165_pdata;
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+- if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
++ if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach SI2165 front end\n");
+ result = -EINVAL;
+@@ -786,12 +808,12 @@ static int dvb_init(struct cx231xx *dev)
+
+ dvb->i2c_client_demod = client;
+
+- dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
++ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- dvb_attach(tda18271_attach, dev->dvb->frontend,
++ dvb_attach(tda18271_attach, dev->dvb->frontend[0],
+ 0x60,
+ tuner_i2c,
+ &hcw_tda18271_config);
+@@ -808,7 +830,7 @@ static int dvb_init(struct cx231xx *dev)
+
+ /* attach demod */
+ memset(&si2165_pdata, 0, sizeof(si2165_pdata));
+- si2165_pdata.fe = &dev->dvb->frontend;
++ si2165_pdata.fe = &dev->dvb->frontend[0];
+ si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT;
+ si2165_pdata.ref_freq_hz = 24000000;
+
+@@ -818,7 +840,7 @@ static int dvb_init(struct cx231xx *dev)
+ info.platform_data = &si2165_pdata;
+ request_module(info.type);
+ client = i2c_new_device(demod_i2c, &info);
+- if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) {
++ if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach SI2165 front end\n");
+ result = -EINVAL;
+@@ -835,14 +857,14 @@ static int dvb_init(struct cx231xx *dev)
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+- dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
++ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+- si2157_config.fe = dev->dvb->frontend;
++ si2157_config.fe = dev->dvb->frontend[0];
+ #ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+ #endif
+@@ -857,14 +879,14 @@ static int dvb_init(struct cx231xx *dev)
+ tuner_i2c,
+ &info);
+ if (client == NULL || client->dev.driver == NULL) {
+- dvb_frontend_detach(dev->dvb->frontend);
++ dvb_frontend_detach(dev->dvb->frontend[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+- dvb_frontend_detach(dev->dvb->frontend);
++ dvb_frontend_detach(dev->dvb->frontend[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+@@ -882,26 +904,26 @@ static int dvb_init(struct cx231xx *dev)
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+- dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
++ dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
+ &hauppauge_955q_lgdt3306a_config,
+ demod_i2c
+ );
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach LGDT3306A frontend.\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+- dev->dvb->frontend->ops.i2c_gate_ctrl = NULL;
++ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+- si2157_config.fe = dev->dvb->frontend;
++ si2157_config.fe = dev->dvb->frontend[0];
+ #ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+ #endif
+@@ -916,14 +938,14 @@ static int dvb_init(struct cx231xx *dev)
+ tuner_i2c,
+ &info);
+ if (client == NULL || client->dev.driver == NULL) {
+- dvb_frontend_detach(dev->dvb->frontend);
++ dvb_frontend_detach(dev->dvb->frontend[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+- dvb_frontend_detach(dev->dvb->frontend);
++ dvb_frontend_detach(dev->dvb->frontend[0]);
+ result = -ENODEV;
+ goto out_free;
+ }
+@@ -933,6 +955,182 @@ static int dvb_init(struct cx231xx *dev)
+ dev->dvb->i2c_client_tuner = client;
+ break;
+ }
++ case CX231XX_BOARD_HAUPPAUGE_935C:
++ {
++ struct i2c_client *client;
++ struct i2c_board_info info;
++ struct si2157_config si2157_config = {};
++ struct si2168_config si2168_config = {};
++ struct i2c_adapter *adapter;
++
++ memset(&info, 0, sizeof(struct i2c_board_info));
++
++ /* attach demodulator chip */
++ memset(&si2168_config, 0, sizeof(si2168_config));
++ si2168_config.ts_mode = SI2168_TS_SERIAL;
++ si2168_config.fe = &dev->dvb->frontend[0];
++ si2168_config.i2c_adapter = &adapter;
++ si2168_config.ts_clock_inv = true;
++
++ strlcpy(info.type, "si2168", sizeof(info.type));
++ info.addr = dev->board.demod_addr;
++ info.platform_data = &si2168_config;
++
++ request_module(info.type);
++ client = i2c_new_device(demod_i2c, &info);
++
++ if (client == NULL || client->dev.driver == NULL) {
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ if (!try_module_get(client->dev.driver->owner)) {
++ i2c_unregister_device(client);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ dvb->i2c_client_demod = client;
++ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
++
++ /* define general-purpose callback pointer */
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
++
++ /* attach tuner */
++ memset(&si2157_config, 0, sizeof(si2157_config));
++ si2157_config.fe = dev->dvb->frontend[0];
++#ifdef CONFIG_MEDIA_CONTROLLER_DVB
++ si2157_config.mdev = dev->media_dev;
++#endif
++ si2157_config.if_port = 1;
++ si2157_config.inversion = true;
++ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
++ info.addr = 0x60;
++ info.platform_data = &si2157_config;
++ request_module("si2157");
++
++ client = i2c_new_device(tuner_i2c, &info);
++ if (client == NULL || client->dev.driver == NULL) {
++ module_put(dvb->i2c_client_demod->dev.driver->owner);
++ i2c_unregister_device(dvb->i2c_client_demod);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ if (!try_module_get(client->dev.driver->owner)) {
++ i2c_unregister_device(client);
++ module_put(dvb->i2c_client_demod->dev.driver->owner);
++ i2c_unregister_device(dvb->i2c_client_demod);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ dev->cx231xx_reset_analog_tuner = NULL;
++ dev->dvb->i2c_client_tuner = client;
++ break;
++ }
++ case CX231XX_BOARD_HAUPPAUGE_975:
++ {
++ struct i2c_client *client;
++ struct i2c_board_info info;
++ struct si2157_config si2157_config = {};
++ struct si2168_config si2168_config = {};
++ struct i2c_adapter *adapter;
++
++ memset(&info, 0, sizeof(struct i2c_board_info));
++
++ /* attach demodulator chip */
++ dev->dvb->frontend[0] = dvb_attach(lgdt3306a_attach,
++ &hauppauge_955q_lgdt3306a_config,
++ demod_i2c
++ );
++
++ if (dev->dvb->frontend[0] == NULL) {
++ dev_err(dev->dev,
++ "Failed to attach LGDT3306A frontend.\n");
++ result = -EINVAL;
++ goto out_free;
++ }
++
++ /* attach demodulator chip */
++ memset(&si2168_config, 0, sizeof(si2168_config));
++ si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
++ si2168_config.fe = &dev->dvb->frontend[1];
++ si2168_config.i2c_adapter = &adapter;
++ si2168_config.ts_clock_inv = true;
++
++ strlcpy(info.type, "si2168", sizeof(info.type));
++ info.addr = dev->board.demod_addr;
++ info.platform_data = &si2168_config;
++
++ request_module(info.type);
++ client = i2c_new_device(demod_i2c, &info);
++ if (client == NULL || client->dev.driver == NULL) {
++ dvb_frontend_detach(dev->dvb->frontend[0]);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ if (!try_module_get(client->dev.driver->owner)) {
++ dvb_frontend_detach(dev->dvb->frontend[0]);
++ i2c_unregister_device(client);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ dvb->i2c_client_demod = client;
++ dev->dvb->frontend[1]->id = 1;
++
++ /* TODO: INSPECT THIS! Required for multiple frontends? */
++ dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;
++ dev->dvb->frontend[1]->ops.i2c_gate_ctrl = NULL;
++
++ /* define general-purpose callback pointer */
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
++ dvb->frontend[1]->callback = cx231xx_tuner_callback;
++
++ /* attach tuner */
++ memset(&si2157_config, 0, sizeof(si2157_config));
++ si2157_config.fe = dev->dvb->frontend[0];
++#ifdef CONFIG_MEDIA_CONTROLLER_DVB
++ si2157_config.mdev = dev->media_dev;
++#endif
++ si2157_config.if_port = 1;
++ si2157_config.inversion = true;
++ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
++ info.addr = 0x60;
++ info.platform_data = &si2157_config;
++ request_module("si2157");
++
++ client = i2c_new_device(tuner_i2c, &info);
++ if (client == NULL || client->dev.driver == NULL) {
++ module_put(dvb->i2c_client_demod->dev.driver->owner);
++ i2c_unregister_device(dvb->i2c_client_demod);
++ dvb_frontend_detach(dev->dvb->frontend[0]);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ if (!try_module_get(client->dev.driver->owner)) {
++ i2c_unregister_device(client);
++ module_put(dvb->i2c_client_demod->dev.driver->owner);
++ i2c_unregister_device(dvb->i2c_client_demod);
++ dvb_frontend_detach(dev->dvb->frontend[0]);
++ result = -ENODEV;
++ goto out_free;
++ }
++
++ dev->dvb->frontend[1]->tuner_priv =
++ dev->dvb->frontend[0]->tuner_priv;
++
++ dvb_attach(si2157_attach, dev->dvb->frontend[1], info.addr,
++ client->adapter, &si2157_config);
++
++ dev->cx231xx_reset_analog_tuner = NULL;
++
++ dev->dvb->i2c_client_tuner = client;
++ break;
++ }
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+ case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
+
+@@ -940,11 +1138,11 @@ static int dvb_init(struct cx231xx *dev)
+ "%s: looking for demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(tuner_i2c));
+
+- dev->dvb->frontend = dvb_attach(mb86a20s_attach,
++ dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
+ &pv_mb86a20s_config,
+ demod_i2c);
+
+- if (dev->dvb->frontend == NULL) {
++ if (dev->dvb->frontend[0] == NULL) {
+ dev_err(dev->dev,
+ "Failed to attach mb86a20s demod\n");
+ result = -EINVAL;
+@@ -952,9 +1150,9 @@ static int dvb_init(struct cx231xx *dev)
+ }
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+- dvb_attach(tda18271_attach, dev->dvb->frontend,
++ dvb_attach(tda18271_attach, dev->dvb->frontend[0],
+ 0x60, tuner_i2c,
+ &pv_tda18271_config);
+ break;
+@@ -969,7 +1167,7 @@ static int dvb_init(struct cx231xx *dev)
+
+ /* attach demodulator chip */
+ si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
+- si2168_config.fe = &dev->dvb->frontend;
++ si2168_config.fe = &dev->dvb->frontend[0];
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.ts_clock_inv = true;
+
+@@ -994,7 +1192,7 @@ static int dvb_init(struct cx231xx *dev)
+ dvb->i2c_client_demod = client;
+
+ /* attach tuner chip */
+- si2157_config.fe = dev->dvb->frontend;
++ si2157_config.fe = dev->dvb->frontend[0];
+ #ifdef CONFIG_MEDIA_CONTROLLER_DVB
+ si2157_config.mdev = dev->media_dev;
+ #endif
+@@ -1037,7 +1235,7 @@ static int dvb_init(struct cx231xx *dev)
+ /* attach demodulator chip */
+ mn88473_config.i2c_wr_max = 16;
+ mn88473_config.xtal = 25000000;
+- mn88473_config.fe = &dev->dvb->frontend;
++ mn88473_config.fe = &dev->dvb->frontend[0];
+
+ strlcpy(info.type, "mn88473", sizeof(info.type));
+ info.addr = dev->board.demod_addr;
+@@ -1060,10 +1258,10 @@ static int dvb_init(struct cx231xx *dev)
+ dvb->i2c_client_demod = client;
+
+ /* define general-purpose callback pointer */
+- dvb->frontend->callback = cx231xx_tuner_callback;
++ dvb->frontend[0]->callback = cx231xx_tuner_callback;
+
+ /* attach tuner chip */
+- dvb_attach(r820t_attach, dev->dvb->frontend,
++ dvb_attach(r820t_attach, dev->dvb->frontend[0],
+ tuner_i2c,
+ &astrometa_t2hybrid_r820t_config);
+ break;
+@@ -1074,7 +1272,7 @@ static int dvb_init(struct cx231xx *dev)
+ dev->name);
+ break;
+ }
+- if (NULL == dvb->frontend) {
++ if (NULL == dvb->frontend[0]) {
+ dev_err(dev->dev,
+ "%s/2: frontend initialization failed\n", dev->name);
+ result = -EINVAL;
+diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
+index 65b039c..fa993f7 100644
+--- a/drivers/media/usb/cx231xx/cx231xx.h
++++ b/drivers/media/usb/cx231xx/cx231xx.h
+@@ -81,6 +81,8 @@
+ #define CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD 23
+ #define CX231XX_BOARD_ASTROMETA_T2HYBRID 24
+ #define CX231XX_BOARD_THE_IMAGING_SOURCE_DFG_USB2_PRO 25
++#define CX231XX_BOARD_HAUPPAUGE_935C 26
++#define CX231XX_BOARD_HAUPPAUGE_975 27
+
+ /* Limits minimum and default number of buffers */
+ #define CX231XX_MIN_BUF 4
+diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
+index 4c57fd7..82c7f8a 100644
+--- a/drivers/media/usb/em28xx/em28xx-cards.c
++++ b/drivers/media/usb/em28xx/em28xx-cards.c
+@@ -508,8 +508,10 @@ static struct em28xx_reg_seq plex_px_bcud[] = {
+ };
+
+ /*
+- * 2040:0265 Hauppauge WinTV-dualHD DVB
+- * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM
++ * 2040:0265 Hauppauge WinTV-dualHD DVB Isoc
++ * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk
++ * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM Isoc
++ * 2040:826d Hauppauge WinTV-dualHD ATSC/QAM Bulk
+ * reg 0x80/0x84:
+ * GPIO_0: Yellow LED tuner 1, 0=on, 1=off
+ * GPIO_1: Green LED tuner 1, 0=on, 1=off
+@@ -2392,7 +2394,8 @@ struct em28xx_board em28xx_boards[] = {
+ .has_dvb = 1,
+ },
+ /*
+- * 2040:0265 Hauppauge WinTV-dualHD (DVB version).
++ * 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc.
++ * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk.
+ * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157
+ */
+ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = {
+@@ -2403,11 +2406,13 @@ struct em28xx_board em28xx_boards[] = {
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = hauppauge_dualhd_dvb,
+ .has_dvb = 1,
++ .has_dual_ts = 1,
+ .ir_codes = RC_MAP_HAUPPAUGE,
+ .leds = hauppauge_dualhd_leds,
+ },
+ /*
+- * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM).
++ * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Isoc.
++ * 2040:826d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) Bulk.
+ * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157
+ */
+ [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = {
+@@ -2418,6 +2423,7 @@ struct em28xx_board em28xx_boards[] = {
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = hauppauge_dualhd_dvb,
+ .has_dvb = 1,
++ .has_dual_ts = 1,
+ .ir_codes = RC_MAP_HAUPPAUGE,
+ .leds = hauppauge_dualhd_leds,
+ },
+@@ -2548,8 +2554,12 @@ struct usb_device_id em28xx_id_table[] = {
+ .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
+ { USB_DEVICE(0x2040, 0x0265),
+ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
++ { USB_DEVICE(0x2040, 0x8265),
++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
+ { USB_DEVICE(0x2040, 0x026d),
+ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 },
++ { USB_DEVICE(0x2040, 0x826d),
++ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 },
+ { USB_DEVICE(0x0438, 0xb002),
+ .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
+ { USB_DEVICE(0x2001, 0xf112),
+@@ -2610,7 +2620,13 @@ struct usb_device_id em28xx_id_table[] = {
+ .driver_info = EM28178_BOARD_PCTV_461E },
+ { USB_DEVICE(0x2013, 0x025f),
+ .driver_info = EM28178_BOARD_PCTV_292E },
+- { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */
++ { USB_DEVICE(0x2013, 0x0264), /* Hauppauge WinTV-soloHD 292e SE */
++ .driver_info = EM28178_BOARD_PCTV_292E },
++ { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD Isoc */
++ .driver_info = EM28178_BOARD_PCTV_292E },
++ { USB_DEVICE(0x2040, 0x8264), /* Hauppauge OEM Generic WinTV-soloHD Bulk */
++ .driver_info = EM28178_BOARD_PCTV_292E },
++ { USB_DEVICE(0x2040, 0x8268), /* Hauppauge Retail WinTV-soloHD Bulk */
+ .driver_info = EM28178_BOARD_PCTV_292E },
+ { USB_DEVICE(0x0413, 0x6f07),
+ .driver_info = EM2861_BOARD_LEADTEK_VC100 },
+@@ -3240,7 +3256,8 @@ static void em28xx_release_resources(struct em28xx *dev)
+ em28xx_i2c_unregister(dev, 1);
+ em28xx_i2c_unregister(dev, 0);
+
+- usb_put_dev(udev);
++ if (dev->ts == PRIMARY_TS)
++ usb_put_dev(udev);
+
+ /* Mark device as unused */
+ clear_bit(dev->devno, em28xx_devused);
+@@ -3433,6 +3450,35 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
+ return 0;
+ }
+
++int em28xx_duplicate_dev(struct em28xx *dev)
++{
++ int nr;
++ struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL);
++
++ if (sec_dev == NULL) {
++ dev->dev_next = NULL;
++ return -ENOMEM;
++ }
++ memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev)));
++ /* Check to see next free device and mark as used */
++ do {
++ nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
++ if (nr >= EM28XX_MAXBOARDS) {
++ /* No free device slots */
++ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
++ EM28XX_MAXBOARDS);
++ kfree(sec_dev);
++ dev->dev_next = NULL;
++ return -ENOMEM;
++ }
++ } while (test_and_set_bit(nr, em28xx_devused));
++ sec_dev->devno = nr;
++ snprintf(sec_dev->name, 28, "em28xx #%d", nr);
++ sec_dev->dev_next = NULL;
++ dev->dev_next = sec_dev;
++ return 0;
++}
++
+ /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+ #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
+
+@@ -3552,6 +3598,17 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ }
+ }
+ break;
++ case 0x85:
++ if (usb_endpoint_xfer_isoc(e)) {
++ if (size > dev->dvb_max_pkt_size_isoc_ts2) {
++ dev->dvb_ep_isoc_ts2 = e->bEndpointAddress;
++ dev->dvb_max_pkt_size_isoc_ts2 = size;
++ dev->dvb_alt_isoc = i;
++ }
++ } else {
++ dev->dvb_ep_bulk_ts2 = e->bEndpointAddress;
++ }
++ break;
+ }
+ }
+ /* NOTE:
+@@ -3566,6 +3623,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ * 0x83 isoc* => audio
+ * 0x84 isoc => digital
+ * 0x84 bulk => analog or digital**
++ * 0x85 isoc => digital TS2
++ * 0x85 bulk => digital TS2
+ * (*: audio should always be isoc)
+ * (**: analog, if ep 0x82 is isoc, otherwise digital)
+ *
+@@ -3633,6 +3692,10 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ dev->has_video = has_video;
+ dev->ifnum = ifnum;
+
++ dev->ts = PRIMARY_TS;
++ snprintf(dev->name, 28, "em28xx");
++ dev->dev_next = NULL;
++
+ if (has_vendor_audio) {
+ dev_err(&interface->dev,
+ "Audio interface %i found (Vendor Class)\n", ifnum);
+@@ -3712,6 +3775,65 @@ static int em28xx_usb_probe(struct usb_interface *interface,
+ dev->dvb_xfer_bulk ? "bulk" : "isoc");
+ }
+
++ if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) {
++ dev->dev_next->ts = SECONDARY_TS;
++ dev->dev_next->alt = -1;
++ dev->dev_next->is_audio_only = has_vendor_audio &&
++ !(has_video || has_dvb);
++ dev->dev_next->has_video = false;
++ dev->dev_next->ifnum = ifnum;
++ dev->dev_next->model = id->driver_info;
++
++ mutex_init(&dev->dev_next->lock);
++ retval = em28xx_init_dev(dev->dev_next, udev, interface,
++ dev->dev_next->devno);
++ if (retval)
++ goto err_free;
++
++ dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */
++ dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */
++
++ if (usb_xfer_mode < 0) {
++ if (dev->dev_next->board.is_webcam)
++ try_bulk = 1;
++ else
++ try_bulk = 0;
++ } else {
++ try_bulk = usb_xfer_mode > 0;
++ }
++
++ /* Select USB transfer types to use */
++ if (has_dvb) {
++ if (!dev->dvb_ep_isoc_ts2 ||
++ (try_bulk && dev->dvb_ep_bulk_ts2))
++ dev->dev_next->dvb_xfer_bulk = 1;
++ dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n",
++ dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc");
++ }
++
++ dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2;
++ dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2;
++ dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
++ dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
++
++ /* Configuare hardware to support TS2*/
++ if (dev->dvb_xfer_bulk) {
++ /* The ep4 and ep5 are configuared for BULK */
++ em28xx_write_reg(dev, 0x0b, 0x96);
++ mdelay(100);
++ em28xx_write_reg(dev, 0x0b, 0x80);
++ mdelay(100);
++ } else {
++ /* The ep4 and ep5 are configuared for ISO */
++ em28xx_write_reg(dev, 0x0b, 0x96);
++ mdelay(100);
++ em28xx_write_reg(dev, 0x0b, 0x82);
++ mdelay(100);
++ }
++
++ kref_init(&dev->dev_next->ref);
++ }
++
+ kref_init(&dev->ref);
+
+ request_modules(dev);
+@@ -3754,15 +3876,29 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
+ if (!dev)
+ return;
+
++ if (dev->dev_next != NULL) {
++ dev->dev_next->disconnected = 1;
++ dev_info(&dev->intf->dev, "Disconnecting %s\n",
++ dev->dev_next->name);
++ flush_request_modules(dev->dev_next);
++ }
++
+ dev->disconnected = 1;
+
+- dev_err(&dev->intf->dev, "Disconnecting\n");
++ dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name);
+
+ flush_request_modules(dev);
+
+ em28xx_close_extension(dev);
+
++ if (dev->dev_next != NULL)
++ em28xx_release_resources(dev->dev_next);
+ em28xx_release_resources(dev);
++
++ if (dev->dev_next != NULL) {
++ kref_put(&dev->dev_next->ref, em28xx_free_device);
++ dev->dev_next = NULL;
++ }
+ kref_put(&dev->ref, em28xx_free_device);
+ }
+
+diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
+index 1d0d8cc..b72335e 100644
+--- a/drivers/media/usb/em28xx/em28xx-core.c
++++ b/drivers/media/usb/em28xx/em28xx-core.c
+@@ -638,10 +638,30 @@ int em28xx_capture_start(struct em28xx *dev, int start)
+ dev->chip_id == CHIP_ID_EM28174 ||
+ dev->chip_id == CHIP_ID_EM28178) {
+ /* The Transport Stream Enable Register moved in em2874 */
+- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
+- start ?
+- EM2874_TS1_CAPTURE_ENABLE : 0x00,
+- EM2874_TS1_CAPTURE_ENABLE);
++ if (dev->dvb_xfer_bulk) {
++ /* Max Tx Size = 188 * EM28XX_DVB_BULK_PACKET_MULTIPLIER */
++ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
++ EM2874_R5D_TS1_PKT_SIZE :
++ EM2874_R5E_TS2_PKT_SIZE,
++ EM28XX_DVB_BULK_PACKET_MULTIPLIER);
++ } else {
++ /* TS2 Maximum Transfer Size = 188 * 5 */
++ em28xx_write_reg(dev, (dev->ts == PRIMARY_TS) ?
++ EM2874_R5D_TS1_PKT_SIZE :
++ EM2874_R5E_TS2_PKT_SIZE, 0x05);
++ }
++ if (dev->ts == PRIMARY_TS)
++ rc = em28xx_write_reg_bits(dev,
++ EM2874_R5F_TS_ENABLE,
++ start ?
++ EM2874_TS1_CAPTURE_ENABLE : 0x00,
++ EM2874_TS1_CAPTURE_ENABLE);
++ else
++ rc = em28xx_write_reg_bits(dev,
++ EM2874_R5F_TS_ENABLE,
++ start ?
++ EM2874_TS2_CAPTURE_ENABLE : 0x00,
++ EM2874_TS2_CAPTURE_ENABLE);
+ } else {
+ /* FIXME: which is the best order? */
+ /* video registers are sampled by VREF */
+@@ -1077,7 +1097,11 @@ int em28xx_register_extension(struct em28xx_ops *ops)
+ mutex_lock(&em28xx_devlist_mutex);
+ list_add_tail(&ops->next, &em28xx_extension_devlist);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+- ops->init(dev);
++ if (ops->init) {
++ ops->init(dev);
++ if (dev->dev_next != NULL)
++ ops->init(dev->dev_next);
++ }
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ pr_info("em28xx: Registered (%s) extension\n", ops->name);
+@@ -1091,7 +1115,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(dev, &em28xx_devlist, devlist) {
+- ops->fini(dev);
++ if (ops->fini) {
++ if (dev->dev_next != NULL)
++ ops->fini(dev->dev_next);
++ ops->fini(dev);
++ }
+ }
+ list_del(&ops->next);
+ mutex_unlock(&em28xx_devlist_mutex);
+@@ -1106,8 +1134,11 @@ void em28xx_init_extension(struct em28xx *dev)
+ mutex_lock(&em28xx_devlist_mutex);
+ list_add_tail(&dev->devlist, &em28xx_devlist);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+- if (ops->init)
++ if (ops->init) {
+ ops->init(dev);
++ if (dev->dev_next != NULL)
++ ops->init(dev->dev_next);
++ }
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ }
+@@ -1118,8 +1149,11 @@ void em28xx_close_extension(struct em28xx *dev)
+
+ mutex_lock(&em28xx_devlist_mutex);
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+- if (ops->fini)
++ if (ops->fini) {
++ if (dev->dev_next != NULL)
++ ops->fini(dev->dev_next);
+ ops->fini(dev);
++ }
+ }
+ list_del(&dev->devlist);
+ mutex_unlock(&em28xx_devlist_mutex);
+@@ -1134,6 +1168,8 @@ int em28xx_suspend_extension(struct em28xx *dev)
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->suspend)
+ ops->suspend(dev);
++ if (dev->dev_next != NULL)
++ ops->suspend(dev->dev_next);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+@@ -1148,6 +1184,8 @@ int em28xx_resume_extension(struct em28xx *dev)
+ list_for_each_entry(ops, &em28xx_extension_devlist, next) {
+ if (ops->resume)
+ ops->resume(dev);
++ if (dev->dev_next != NULL)
++ ops->resume(dev->dev_next);
+ }
+ mutex_unlock(&em28xx_devlist_mutex);
+ return 0;
+diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
+index c4abf51..a7447e9 100644
+--- a/drivers/media/usb/em28xx/em28xx-dvb.c
++++ b/drivers/media/usb/em28xx/em28xx-dvb.c
+@@ -199,13 +199,12 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
+ int rc;
+ struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
+ struct em28xx *dev = i2c_bus->dev;
+- struct usb_device *udev = interface_to_usbdev(dev->intf);
+ int dvb_max_packet_size, packet_multiplier, dvb_alt;
+
+ if (dev->dvb_xfer_bulk) {
+ if (!dev->dvb_ep_bulk)
+ return -ENODEV;
+- dvb_max_packet_size = 512; /* USB 2.0 spec */
++ dvb_max_packet_size = 188;
+ packet_multiplier = EM28XX_DVB_BULK_PACKET_MULTIPLIER;
+ dvb_alt = 0;
+ } else { /* isoc */
+@@ -218,7 +217,6 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
+ dvb_alt = dev->dvb_alt_isoc;
+ }
+
+- usb_set_interface(udev, dev->ifnum, dvb_alt);
+ rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+@@ -1128,8 +1126,9 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
+
+ static int em28xx_dvb_init(struct em28xx *dev)
+ {
+- int result = 0;
++ int result = 0, dvb_alt = 0;
+ struct em28xx_dvb *dvb;
++ struct usb_device *udev;
+
+ if (dev->is_audio_only) {
+ /* Shouldn't initialize IR for this interface */
+@@ -1155,7 +1154,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+ dev->dvb_xfer_bulk,
+ EM28XX_DVB_NUM_BUFS,
+- 512,
++ 188,
+ EM28XX_DVB_BULK_PACKET_MULTIPLIER);
+ } else {
+ result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+@@ -1728,6 +1727,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
++ si2168_config.inversion = true;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+@@ -1912,9 +1912,13 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ si2168_config.ts_mode = SI2168_TS_SERIAL;
++ si2168_config.inversion = true;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+- info.addr = 0x64;
++ if (dev->ts == PRIMARY_TS)
++ info.addr = 0x64;
++ else
++ info.addr = 0x67;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+@@ -1940,7 +1944,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ #endif
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+- info.addr = 0x60;
++ if (dev->ts == PRIMARY_TS)
++ info.addr = 0x60;
++ else
++ info.addr = 0x63;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+ client = i2c_new_device(adapter, &info);
+@@ -1976,7 +1983,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ lgdt3306a_config.fe = &dvb->fe[0];
+ lgdt3306a_config.i2c_adapter = &adapter;
+ strlcpy(info.type, "lgdt3306a", sizeof(info.type));
+- info.addr = 0x59;
++ if (dev->ts == PRIMARY_TS)
++ info.addr = 0x59;
++ else
++ info.addr = 0x0e;
+ info.platform_data = &lgdt3306a_config;
+ request_module(info.type);
+ client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
+@@ -2003,7 +2013,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ #endif
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", sizeof(info.type));
+- info.addr = 0x60;
++ if (dev->ts == PRIMARY_TS)
++ info.addr = 0x60;
++ else
++ info.addr = 0x62;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+
+@@ -2046,6 +2059,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
+ if (result < 0)
+ goto out_free;
+
++ if (dev->dvb_xfer_bulk) {
++ dvb_alt = 0;
++ } else { /* isoc */
++ dvb_alt = dev->dvb_alt_isoc;
++ }
++
++ udev = interface_to_usbdev(dev->intf);
++ usb_set_interface(udev, dev->ifnum, dvb_alt);
+ dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");
+
+ kref_get(&dev->ref);
+diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
+index 88084f2..7dcf0cb 100644
+--- a/drivers/media/usb/em28xx/em28xx.h
++++ b/drivers/media/usb/em28xx/em28xx.h
+@@ -166,7 +166,7 @@
+ #define EM28XX_STOP_AUDIO 0
+
+ /* maximum number of em28xx boards */
+-#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
++#define EM28XX_MAXBOARDS DVB_MAX_ADAPTERS /* All adapters could be em28xx */
+
+ /* maximum number of frames that can be queued */
+ #define EM28XX_NUM_FRAMES 5
+@@ -191,7 +191,7 @@
+ USB 2.0 spec says bulk packet size is always 512 bytes
+ */
+ #define EM28XX_BULK_PACKET_MULTIPLIER 384
+-#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384
++#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 240
+
+ #define EM28XX_INTERLACED_DEFAULT 1
+
+@@ -217,6 +217,9 @@
+ /* max. number of button state polling addresses */
+ #define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5
+
++#define PRIMARY_TS 0
++#define SECONDARY_TS 1
++
+ enum em28xx_mode {
+ EM28XX_SUSPEND,
+ EM28XX_ANALOG_MODE,
+@@ -457,6 +460,7 @@ struct em28xx_board {
+ unsigned int mts_firmware:1;
+ unsigned int max_range_640_480:1;
+ unsigned int has_dvb:1;
++ unsigned int has_dual_ts:1;
+ unsigned int is_webcam:1;
+ unsigned int valid:1;
+ unsigned int has_ir_i2c:1;
+@@ -621,6 +625,7 @@ struct em28xx {
+ unsigned int is_audio_only:1;
+ enum em28xx_int_audio_type int_audio_type;
+ enum em28xx_usb_audio_type usb_audio_type;
++ unsigned char name[32];
+
+ struct em28xx_board board;
+
+@@ -682,6 +687,8 @@ struct em28xx {
+ u8 ifnum; /* number of the assigned usb interface */
+ u8 analog_ep_isoc; /* address of isoc endpoint for analog */
+ u8 analog_ep_bulk; /* address of bulk endpoint for analog */
++ u8 dvb_ep_isoc_ts2; /* address of isoc endpoint for DVB TS2*/
++ u8 dvb_ep_bulk_ts2; /* address of bulk endpoint for DVB TS2*/
+ u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
+ u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */
+ int alt; /* alternate setting */
+@@ -695,6 +702,8 @@ struct em28xx {
+ int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */
+ unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the
+ selected DVB ep at dvb_alt */
++ unsigned int dvb_max_pkt_size_isoc_ts2; /* isoc max packet size of the
++ selected DVB ep at dvb_alt */
+ unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc
+ transfers for DVB */
+ char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
+@@ -726,6 +735,9 @@ struct em28xx {
+ struct media_entity input_ent[MAX_EM28XX_INPUT];
+ struct media_pad input_pad[MAX_EM28XX_INPUT];
+ #endif
++
++ struct em28xx *dev_next;
++ int ts;
+ };
+
+ #define kref_to_dev(d) container_of(d, struct em28xx, ref)
+diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
+index 82852f2..f5d442d 100644
+--- a/drivers/media/v4l2-core/tuner-core.c
++++ b/drivers/media/v4l2-core/tuner-core.c
+@@ -40,6 +40,7 @@
+ #include "xc5000.h"
+ #include "tda18271.h"
+ #include "xc4000.h"
++#include "si2157.h"
+
+ #define UNSET (-1U)
+
+@@ -396,6 +397,26 @@ static void set_type(struct i2c_client *c, unsigned int type,
+ tune_now = 0;
+ break;
+ }
++ case TUNER_SILABS_SI2157:
++ {
++ static struct si2157_config silabs_config = {
++ .inversion = true,
++ .if_port = 1, /* selects the digital IF port */
++ /* analog assumed to be other port */
++ };
++
++ dprintk("%s: looking for si2157 tuner on i2c bus: %d\n",
++ __func__, i2c_adapter_id(t->i2c->adapter));
++
++ if (!dvb_attach(si2157_attach, &t->fe, t->i2c->addr,
++ t->i2c->adapter, &silabs_config)) {
++ dprintk("%s: attaching si2157 tuner failed\n", __func__);
++ goto attach_failed;
++ }
++ dprintk("%s: si2157 tuner attached\n", __func__);
++ tune_now = 0;
++ break;
++ }
+ default:
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
+diff --git a/include/media/tuner.h b/include/media/tuner.h
+index b3edc14..cab980a 100644
+--- a/include/media/tuner.h
++++ b/include/media/tuner.h
+@@ -142,6 +142,8 @@
+ #define TUNER_SONY_BTF_PK467Z 90 /* NTSC_JP */
+ #define TUNER_SONY_BTF_PB463Z 91 /* NTSC */
+
++#define TUNER_SILABS_SI2157 92 /* Silicon Labs terrestrial/cable tuner series */
++
+ /* tv card specific */
+ #define TDA9887_PRESENT (1<<0)
+ #define TDA9887_PORT1_INACTIVE (1<<1)
+--
+2.14.1
+
diff --git a/packages/linux-driver-addons/dvb/hauppauge/sources/backports/temp_revert.patch b/packages/linux-driver-addons/dvb/hauppauge/sources/backports/temp_revert.patch
new file mode 100644
index 0000000000..1ebe3ac3f6
--- /dev/null
+++ b/packages/linux-driver-addons/dvb/hauppauge/sources/backports/temp_revert.patch
@@ -0,0 +1,30 @@
+reverted: pvrusb2: properly check endpoint types
+
+--- b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
++++ a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+@@ -3648,12 +3648,6 @@
+ hdw);
+ hdw->ctl_write_urb->actual_length = 0;
+ hdw->ctl_write_pend_flag = !0;
+- if (usb_urb_ep_type_check(hdw->ctl_write_urb)) {
+- pvr2_trace(
+- PVR2_TRACE_ERROR_LEGS,
+- "Invalid write control endpoint");
+- return -EINVAL;
+- }
+ status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL);
+ if (status < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+@@ -3678,12 +3672,6 @@
+ hdw);
+ hdw->ctl_read_urb->actual_length = 0;
+ hdw->ctl_read_pend_flag = !0;
+- if (usb_urb_ep_type_check(hdw->ctl_read_urb)) {
+- pvr2_trace(
+- PVR2_TRACE_ERROR_LEGS,
+- "Invalid read control endpoint");
+- return -EINVAL;
+- }
+ status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL);
+ if (status < 0) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
diff --git a/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch b/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch
deleted file mode 100644
index dfd0a88c2b..0000000000
--- a/packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch
+++ /dev/null
@@ -1,17 +0,0 @@
---- a/backports/backports.txt
-+++ b/backports/backports.txt
-@@ -25,6 +25,14 @@ add api_version.patch
- add pr_fmt.patch
- add debug.patch
- add drx39xxj.patch
-+add linux-054-nuvoton_revert_d7b290a1056c5564eec8a1b169c6e84ff3.6.114c13.patch
-+add linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch
-+add linux-062-imon_pad_ignore_diagonal.patch
-+add linux-202-lnbp22_patch_for_more_power_if_rotor.patch
-+add linux-203-stb0899_enable_low_symbol_rate.patch
-+add linux-204-lirc_fix_for_4.12.patch
-+add linux-220-hauppauge_dualhd_second_tuner_support.patch
-+add cxd2880-support.patch
-
- [4.10.255]
- add v4.10_sched_signal.patch
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-054-nuvoton_revert_d7b290a1056c5564eec8a1b169c6e84ff3.6.114c13.patch b/packages/linux-drivers/media_build/sources/backports/linux-054-nuvoton_revert_d7b290a1056c5564eec8a1b169c6e84ff3.6.114c13.patch
deleted file mode 100644
index 08566d1f13..0000000000
--- a/packages/linux-drivers/media_build/sources/backports/linux-054-nuvoton_revert_d7b290a1056c5564eec8a1b169c6e84ff3.6.114c13.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-diff -Naur linux-3.0/drivers/media/rc/nuvoton-cir.c linux-3.0.patch/drivers/media/rc/nuvoton-cir.c
---- linux-3.0/drivers/media/rc/nuvoton-cir.c 2011-07-22 04:17:23.000000000 +0200
-+++ linux-3.0.patch/drivers/media/rc/nuvoton-cir.c 2011-07-22 21:30:48.374591146 +0200
-@@ -1110,7 +1110,7 @@
- rdev->dev.parent = &pdev->dev;
- rdev->driver_name = NVT_DRIVER_NAME;
- rdev->map_name = RC_MAP_RC6_MCE;
-- rdev->timeout = MS_TO_NS(100);
-+ rdev->timeout = US_TO_NS(1000);
- /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
- rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
- #if 0
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch b/packages/linux-drivers/media_build/sources/backports/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch
deleted file mode 100644
index 6b09bc0073..0000000000
--- a/packages/linux-drivers/media_build/sources/backports/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch
+++ /dev/null
@@ -1,28 +0,0 @@
---- linux/drivers/media/rc/ir-rc6-decoder.c 2012-11-25 22:08:13.148418669 -0800
-+++ linux.patch/drivers/media/rc/ir-rc6-decoder.c 2012-11-25 22:07:48.864417975 -0800
-@@ -39,7 +39,6 @@
- #define RC6_STARTBIT_MASK 0x08 /* for the header bits */
- #define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
- #define RC6_6A_LCC_MASK 0xffff0000 /* RC6-6A-32 long customer code mask */
--#define RC6_6A_MCE_CC 0x800f0000 /* MCE customer code */
- #ifndef CHAR_BIT
- #define CHAR_BIT 8 /* Normally in */
- #endif
-@@ -257,14 +256,9 @@ again:
- toggle = 0;
- break;
- case 32:
-- if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
-- protocol = RC_TYPE_RC6_MCE;
-- toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
-- scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
-- } else {
-- protocol = RC_TYPE_RC6_6A_32;
-- toggle = 0;
-- }
-+ protocol = RC_TYPE_RC6_MCE;
-+ toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
-+ scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
- break;
- default:
- IR_dprintk(1, "RC6(6A) unsupported length\n");
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-062-imon_pad_ignore_diagonal.patch b/packages/linux-drivers/media_build/sources/backports/linux-062-imon_pad_ignore_diagonal.patch
deleted file mode 100644
index 677de3ed7f..0000000000
--- a/packages/linux-drivers/media_build/sources/backports/linux-062-imon_pad_ignore_diagonal.patch
+++ /dev/null
@@ -1,21 +0,0 @@
-diff -Naur linux-3.16.1/drivers/media/rc/imon.c linux-3.16.1.patch/drivers/media/rc/imon.c
---- linux-3.16.1/drivers/media/rc/imon.c 2014-08-14 04:36:35.000000000 +0200
-+++ linux-3.16.1.patch/drivers/media/rc/imon.c 2014-08-15 13:57:16.587620642 +0200
-@@ -1344,6 +1344,17 @@
- }
- } else {
- /*
-+ * For users without stabilized, just ignore any value getting
-+ * to close to the diagonal.
-+ */
-+ if ((abs(rel_y) < 2 && abs(rel_x) < 2) ||
-+ abs(abs(rel_y) - abs(rel_x)) < 2 ) {
-+ spin_lock_irqsave(&ictx->kc_lock, flags);
-+ ictx->kc = KEY_UNKNOWN;
-+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
-+ return;
-+ }
-+ /*
- * Hack alert: instead of using keycodes, we have
- * to use hard-coded scancodes here...
- */
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-203-stb0899_enable_low_symbol_rate.patch b/packages/linux-drivers/media_build/sources/backports/linux-203-stb0899_enable_low_symbol_rate.patch
deleted file mode 100644
index 3624c9fa00..0000000000
--- a/packages/linux-drivers/media_build/sources/backports/linux-203-stb0899_enable_low_symbol_rate.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/drivers/media/dvb-frontends/stb0899_drv.c
-+++ b/drivers/media/dvb-frontends/stb0899_drv.c
-@@ -1618,7 +1618,7 @@ static const struct dvb_frontend_ops stb0899_ops = {
- .frequency_max = 2150000,
- .frequency_stepsize = 0,
- .frequency_tolerance = 0,
-- .symbol_rate_min = 5000000,
-+ .symbol_rate_min = 1000000,
- .symbol_rate_max = 45000000,
-
- .caps = FE_CAN_INVERSION_AUTO |
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-204-lirc_fix_for_4.12.patch b/packages/linux-drivers/media_build/sources/backports/linux-204-lirc_fix_for_4.12.patch
deleted file mode 100644
index 7f5694afe0..0000000000
--- a/packages/linux-drivers/media_build/sources/backports/linux-204-lirc_fix_for_4.12.patch
+++ /dev/null
@@ -1,24 +0,0 @@
-Subject: [media] lirc: LIRC_GET_REC_RESOLUTION should return microseconds
-Date: Tue, 11 Jul 2017 10:47:37 +0100
-
-Since commit e8f4818895b3 ("[media] lirc: advertise
-LIRC_CAN_GET_REC_RESOLUTION and improve") lircd uses the ioctl
-LIRC_GET_REC_RESOLUTION to determine the shortest pulse or space that
-the hardware can detect. This breaks decoding in lirc because lircd
-expects the answer in microseconds, but nanoseconds is returned.
-
-drop at bump to 4.13
-
-diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
-index a30af91..d2223c0 100644
---- a/drivers/media/rc/ir-lirc-codec.c
-+++ b/drivers/media/rc/ir-lirc-codec.c
-@@ -266,7 +266,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
- if (!dev->rx_resolution)
- return -ENOTTY;
-
-- val = dev->rx_resolution;
-+ val = dev->rx_resolution / 1000;
- break;
-
- case LIRC_SET_WIDEBAND_RECEIVER:
diff --git a/packages/linux-drivers/media_build/sources/backports/linux-220-hauppauge_dualhd_second_tuner_support.patch b/packages/linux-drivers/media_build/sources/backports/linux-220-hauppauge_dualhd_second_tuner_support.patch
deleted file mode 100644
index 46200b9b6c..0000000000
--- a/packages/linux-drivers/media_build/sources/backports/linux-220-hauppauge_dualhd_second_tuner_support.patch
+++ /dev/null
@@ -1,586 +0,0 @@
-From: Brad Love
-Date: Sun, 16 Apr 2017 00:13:39 -0500
-Subject: Hauppauge DualHD DVB/ATSC second tuner support
-
-diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c
-index c9b1eb3..c50769f 100644
---- a/drivers/media/dvb-frontends/lgdt3306a.c
-+++ b/drivers/media/dvb-frontends/lgdt3306a.c
-@@ -624,6 +624,9 @@ static int lgdt3306a_set_modulation(struct lgdt3306a_state *state,
- case QAM_256:
- ret = lgdt3306a_set_qam(state, QAM_256);
- break;
-+ case QAM_AUTO:
-+ ret = lgdt3306a_set_qam(state, QAM_64);
-+ break;
- default:
- return -EINVAL;
- }
-@@ -649,6 +652,7 @@ static int lgdt3306a_agc_setup(struct lgdt3306a_state *state,
- break;
- case QAM_64:
- case QAM_256:
-+ case QAM_AUTO:
- break;
- default:
- return -EINVAL;
-@@ -703,6 +707,7 @@ static int lgdt3306a_spectral_inversion(struct lgdt3306a_state *state,
- break;
- case QAM_64:
- case QAM_256:
-+ case QAM_AUTO:
- /* Auto ok for QAM */
- ret = lgdt3306a_set_inversion_auto(state, 1);
- break;
-@@ -726,6 +731,7 @@ static int lgdt3306a_set_if(struct lgdt3306a_state *state,
- break;
- case QAM_64:
- case QAM_256:
-+ case QAM_AUTO:
- if_freq_khz = state->cfg->qam_if_khz;
- break;
- default:
-@@ -1644,6 +1650,9 @@ static int lgdt3306a_read_signal_strength(struct dvb_frontend *fe,
- case QAM_256:
- ref_snr = 2800; /* 28dB */
- break;
-+ case QAM_AUTO:
-+ ref_snr = 2200; /* 22dB */
-+ break;
- default:
- return -EINVAL;
- }
-diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
-index 146341a..d2e5b8d 100644
---- a/drivers/media/usb/em28xx/em28xx-cards.c
-+++ b/drivers/media/usb/em28xx/em28xx-cards.c
-@@ -508,8 +508,10 @@ static struct em28xx_reg_seq plex_px_bcud[] = {
- };
-
- /*
-- * 2040:0265 Hauppauge WinTV-dualHD DVB
-- * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM
-+ * 2040:0265 Hauppauge WinTV-dualHD DVB ISOC
-+ * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk
-+ * 2040:026d Hauppauge WinTV-dualHD ATSC/QAM ISOC
-+ * 2040:826d Hauppauge WinTV-dualHD ATSC/QAM Bulk
- * reg 0x80/0x84:
- * GPIO_0: Yellow LED tuner 1, 0=on, 1=off
- * GPIO_1: Green LED tuner 1, 0=on, 1=off
-@@ -2376,7 +2378,8 @@ struct em28xx_board em28xx_boards[] = {
- .has_dvb = 1,
- },
- /*
-- * 2040:0265 Hauppauge WinTV-dualHD (DVB version).
-+ * 2040:0265 Hauppauge WinTV-dualHD (DVB version) ISOC.
-+ * 2040:8265 Hauppauge WinTV-dualHD (DVB version) BULK.
- * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157
- */
- [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = {
-@@ -2387,11 +2390,13 @@ struct em28xx_board em28xx_boards[] = {
- .tuner_type = TUNER_ABSENT,
- .tuner_gpio = hauppauge_dualhd_dvb,
- .has_dvb = 1,
-+ .has_dual_ts = 1,
- .ir_codes = RC_MAP_HAUPPAUGE,
- .leds = hauppauge_dualhd_leds,
- },
- /*
-- * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM).
-+ * 2040:026d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) ISOC.
-+ * 2040:826d Hauppauge WinTV-dualHD (model 01595 - ATSC/QAM) BULK.
- * Empia EM28274, 2x LG LGDT3306A, 2x Silicon Labs Si2157
- */
- [EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595] = {
-@@ -2402,6 +2407,7 @@ struct em28xx_board em28xx_boards[] = {
- .tuner_type = TUNER_ABSENT,
- .tuner_gpio = hauppauge_dualhd_dvb,
- .has_dvb = 1,
-+ .has_dual_ts = 1,
- .ir_codes = RC_MAP_HAUPPAUGE,
- .leds = hauppauge_dualhd_leds,
- },
-@@ -2530,8 +2536,12 @@ struct usb_device_id em28xx_id_table[] = {
- .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 },
- { USB_DEVICE(0x2040, 0x0265),
- .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
-+ { USB_DEVICE(0x2040, 0x8265),
-+ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
- { USB_DEVICE(0x2040, 0x026d),
- .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 },
-+ { USB_DEVICE(0x2040, 0x826d),
-+ .driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595 },
- { USB_DEVICE(0x0438, 0xb002),
- .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 },
- { USB_DEVICE(0x2001, 0xf112),
-@@ -3222,7 +3232,8 @@ static void em28xx_release_resources(struct em28xx *dev)
- em28xx_i2c_unregister(dev, 1);
- em28xx_i2c_unregister(dev, 0);
-
-- usb_put_dev(udev);
-+ if(dev->ts == PRIMARY_TS)
-+ usb_put_dev(udev);
-
- /* Mark device as unused */
- clear_bit(dev->devno, em28xx_devused);
-@@ -3415,6 +3426,34 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
- return 0;
- }
-
-+int em28xx_duplicate_dev(struct em28xx *dev)
-+{
-+ int nr;
-+ struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL);
-+ if (sec_dev == NULL) {
-+ dev->dev_next = NULL;
-+ return -ENOMEM;
-+ }
-+ memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev)));
-+ /* Check to see next free device and mark as used */
-+ do {
-+ nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
-+ if (nr >= EM28XX_MAXBOARDS) {
-+ /* No free device slots */
-+ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
-+ EM28XX_MAXBOARDS);
-+ kfree(sec_dev);
-+ dev->dev_next = NULL;
-+ return -ENOMEM;
-+ }
-+ } while (test_and_set_bit(nr, em28xx_devused));
-+ sec_dev->devno = nr;
-+ snprintf(sec_dev->name, 28, "em28xx #%d", nr);
-+ sec_dev->dev_next = NULL;
-+ dev->dev_next = sec_dev;
-+ return 0;
-+}
-+
- /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
- #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
-
-@@ -3428,7 +3467,8 @@ static int em28xx_usb_probe(struct usb_interface *interface,
- struct usb_device *udev;
- struct em28xx *dev = NULL;
- int retval;
-- bool has_vendor_audio = false, has_video = false, has_dvb = false;
-+ bool has_vendor_audio = false, has_video = false;
-+ bool has_dvb = false, has_dvb_ts2 = false;
- int i, nr, try_bulk;
- const int ifnum = interface->altsetting[0].desc.bInterfaceNumber;
- char *speed;
-@@ -3534,6 +3574,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
- }
- }
- break;
-+ case 0x85:
-+ if (usb_endpoint_xfer_isoc(e)) {
-+ if (size > dev->dvb_max_pkt_size_isoc_ts2) {
-+ has_dvb_ts2 = true; /* see NOTE (~) */
-+ dev->dvb_ep_isoc_ts2 = e->bEndpointAddress;
-+ dev->dvb_max_pkt_size_isoc_ts2 = size;
-+ dev->dvb_alt_isoc = i;
-+ }
-+ } else {
-+ has_dvb_ts2 = true;
-+ dev->dvb_ep_bulk_ts2 = e->bEndpointAddress;
-+ }
-+ break;
- }
- }
- /* NOTE:
-@@ -3615,6 +3668,10 @@ static int em28xx_usb_probe(struct usb_interface *interface,
- dev->has_video = has_video;
- dev->ifnum = ifnum;
-
-+ dev->ts = PRIMARY_TS;
-+ snprintf(dev->name, 28, "em28xx");
-+ dev->dev_next = NULL;
-+
- if (has_vendor_audio) {
- dev_err(&interface->dev,
- "Audio interface %i found (Vendor Class)\n", ifnum);
-@@ -3694,6 +3751,61 @@ static int em28xx_usb_probe(struct usb_interface *interface,
- dev->dvb_xfer_bulk ? "bulk" : "isoc");
- }
-
-+ if(dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0)
-+ {
-+ dev->dev_next->ts = SECONDARY_TS;
-+ dev->dev_next->alt = -1;
-+ dev->dev_next->is_audio_only = has_vendor_audio && !(has_video || has_dvb);
-+ dev->dev_next->has_video = false;
-+ dev->dev_next->ifnum = ifnum;
-+ dev->dev_next->model = id->driver_info;
-+
-+ mutex_init(&dev->dev_next->lock);
-+ retval = em28xx_init_dev(dev->dev_next, udev, interface, dev->dev_next->devno);
-+ if (retval) {
-+ goto err_free;
-+ }
-+
-+ if (usb_xfer_mode < 0) {
-+ if (dev->dev_next->board.is_webcam)
-+ try_bulk = 1;
-+ else
-+ try_bulk = 0;
-+ } else {
-+ try_bulk = usb_xfer_mode > 0;
-+ }
-+
-+ /* Select USB transfer types to use */
-+ if (has_dvb) {
-+ if (!dev->dvb_ep_isoc_ts2 || (try_bulk && dev->dvb_ep_bulk_ts2))
-+ dev->dev_next->dvb_xfer_bulk = 1;
-+ dev_info(&dev->intf->dev, "dvb ts2 set to %s mode.\n",
-+ dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc");
-+ }
-+
-+ dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2;
-+ dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2;
-+ dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
-+ dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
-+
-+ /* Configuare hardware to support TS2*/
-+ if(dev->dvb_xfer_bulk) {
-+ /* The ep4 and ep5 are configuared for BULK */
-+ em28xx_write_reg(dev, 0x0b, 0x96);
-+ mdelay(100);
-+ em28xx_write_reg(dev, 0x0b, 0x80);
-+ mdelay(100);
-+ } else {
-+ /* The ep4 and ep5 are configuared for ISO */
-+ em28xx_write_reg(dev, 0x0b, 0x96);
-+ mdelay(100);
-+ em28xx_write_reg(dev, 0x0b, 0x82);
-+ mdelay(100);
-+ }
-+
-+ kref_init(&dev->dev_next->ref);
-+ }
-+
- kref_init(&dev->ref);
-
- request_modules(dev);
-@@ -3736,15 +3848,28 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
- if (!dev)
- return;
-
-+ if(dev->dev_next!=NULL) {
-+ dev->dev_next->disconnected = 1;
-+ dev_info(&dev->intf->dev, "Disconnecting %s\n", dev->dev_next->name);
-+ flush_request_modules(dev->dev_next);
-+ }
-+
- dev->disconnected = 1;
-
-- dev_err(&dev->intf->dev, "Disconnecting\n");
-+ dev_err(&dev->intf->dev, "Disconnecting %s\n", dev->name);
-
- flush_request_modules(dev);
-
- em28xx_close_extension(dev);
-
-+ if(dev->dev_next!=NULL)
-+ em28xx_release_resources(dev->dev_next);
- em28xx_release_resources(dev);
-+
-+ if(dev->dev_next!=NULL) {
-+ kref_put(&dev->dev_next->ref, em28xx_free_device);
-+ dev->dev_next = NULL;
-+ }
- kref_put(&dev->ref, em28xx_free_device);
- }
-
-diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
-index 1d0d8cc..ca0ddd5 100644
---- a/drivers/media/usb/em28xx/em28xx-core.c
-+++ b/drivers/media/usb/em28xx/em28xx-core.c
-@@ -638,10 +638,39 @@ int em28xx_capture_start(struct em28xx *dev, int start)
- dev->chip_id == CHIP_ID_EM28174 ||
- dev->chip_id == CHIP_ID_EM28178) {
- /* The Transport Stream Enable Register moved in em2874 */
-- rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
-- start ?
-- EM2874_TS1_CAPTURE_ENABLE : 0x00,
-- EM2874_TS1_CAPTURE_ENABLE);
-+ if(dev->dvb_xfer_bulk) {
-+ /* TS1 Maximum Transfer Size = 188 * EM28XX_DVB_BULK_PACKET_MULTIPLIER */
-+ em28xx_write_reg(dev, EM2874_R5D_TS1_PKT_SIZE, 0xef);
-+ } else {
-+ /* TS1 Maximum Transfer Size = 188 * 5 */
-+ em28xx_write_reg(dev, EM2874_R5D_TS1_PKT_SIZE, 0x05);
-+ }
-+
-+ if(dev->board.has_dual_ts) {
-+ if(start) {
-+ if(dev->dvb_xfer_bulk) {
-+ /* TS2 Maximum Transfer Size = 188 * EM28XX_DVB_BULK_PACKET_MULTIPLIER */
-+ em28xx_write_reg(dev, EM2874_R5E_TS2_PKT_SIZE, 0xef);
-+ } else {
-+ /* TS2 Maximum Transfer Size = 188 * 5 */
-+ em28xx_write_reg(dev, EM2874_R5E_TS2_PKT_SIZE, 0x05);
-+ }
-+ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
-+ (EM2874_TS1_CAPTURE_ENABLE | EM2874_TS2_CAPTURE_ENABLE),
-+ (EM2874_TS1_CAPTURE_ENABLE | EM2874_TS2_CAPTURE_ENABLE));
-+ } else {
-+ if(dev->ts == PRIMARY_TS) {
-+ rc = em28xx_toggle_reg_bits(dev, EM2874_R5F_TS_ENABLE, EM2874_TS1_CAPTURE_ENABLE);
-+ } else {
-+ rc = em28xx_toggle_reg_bits(dev, EM2874_R5F_TS_ENABLE, EM2874_TS2_CAPTURE_ENABLE);
-+ }
-+ }
-+ } else {
-+ rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
-+ start ?
-+ EM2874_TS1_CAPTURE_ENABLE : 0x00,
-+ EM2874_TS1_CAPTURE_ENABLE);
-+ }
- } else {
- /* FIXME: which is the best order? */
- /* video registers are sampled by VREF */
-@@ -1077,7 +1106,11 @@ int em28xx_register_extension(struct em28xx_ops *ops)
- mutex_lock(&em28xx_devlist_mutex);
- list_add_tail(&ops->next, &em28xx_extension_devlist);
- list_for_each_entry(dev, &em28xx_devlist, devlist) {
-- ops->init(dev);
-+ if (ops->init) {
-+ ops->init(dev);
-+ if(dev->dev_next!=NULL)
-+ ops->init(dev->dev_next);
-+ }
- }
- mutex_unlock(&em28xx_devlist_mutex);
- pr_info("em28xx: Registered (%s) extension\n", ops->name);
-@@ -1091,7 +1124,11 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
-
- mutex_lock(&em28xx_devlist_mutex);
- list_for_each_entry(dev, &em28xx_devlist, devlist) {
-- ops->fini(dev);
-+ if (ops->fini) {
-+ if(dev->dev_next!=NULL)
-+ ops->fini(dev->dev_next);
-+ ops->fini(dev);
-+ }
- }
- list_del(&ops->next);
- mutex_unlock(&em28xx_devlist_mutex);
-@@ -1106,8 +1143,11 @@ void em28xx_init_extension(struct em28xx *dev)
- mutex_lock(&em28xx_devlist_mutex);
- list_add_tail(&dev->devlist, &em28xx_devlist);
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-- if (ops->init)
-+ if (ops->init) {
- ops->init(dev);
-+ if(dev->dev_next!=NULL)
-+ ops->init(dev->dev_next);
-+ }
- }
- mutex_unlock(&em28xx_devlist_mutex);
- }
-@@ -1118,8 +1158,11 @@ void em28xx_close_extension(struct em28xx *dev)
-
- mutex_lock(&em28xx_devlist_mutex);
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
-- if (ops->fini)
-+ if (ops->fini) {
-+ if(dev->dev_next!=NULL)
-+ ops->fini(dev->dev_next);
- ops->fini(dev);
-+ }
- }
- list_del(&dev->devlist);
- mutex_unlock(&em28xx_devlist_mutex);
-@@ -1134,6 +1177,8 @@ int em28xx_suspend_extension(struct em28xx *dev)
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->suspend)
- ops->suspend(dev);
-+ if(dev->dev_next!=NULL)
-+ ops->suspend(dev->dev_next);
- }
- mutex_unlock(&em28xx_devlist_mutex);
- return 0;
-@@ -1148,6 +1193,8 @@ int em28xx_resume_extension(struct em28xx *dev)
- list_for_each_entry(ops, &em28xx_extension_devlist, next) {
- if (ops->resume)
- ops->resume(dev);
-+ if(dev->dev_next!=NULL)
-+ ops->resume(dev->dev_next);
- }
- mutex_unlock(&em28xx_devlist_mutex);
- return 0;
-diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
-index 82edd37..e10b1ac 100644
---- a/drivers/media/usb/em28xx/em28xx-dvb.c
-+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
-@@ -199,13 +199,13 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
- int rc;
- struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv;
- struct em28xx *dev = i2c_bus->dev;
-- struct usb_device *udev = interface_to_usbdev(dev->intf);
-+// struct usb_device *udev = interface_to_usbdev(dev->intf);
- int dvb_max_packet_size, packet_multiplier, dvb_alt;
-
- if (dev->dvb_xfer_bulk) {
- if (!dev->dvb_ep_bulk)
- return -ENODEV;
-- dvb_max_packet_size = 512; /* USB 2.0 spec */
-+ dvb_max_packet_size = 188;
- packet_multiplier = EM28XX_DVB_BULK_PACKET_MULTIPLIER;
- dvb_alt = 0;
- } else { /* isoc */
-@@ -218,7 +218,8 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
- dvb_alt = dev->dvb_alt_isoc;
- }
-
-- usb_set_interface(udev, dev->ifnum, dvb_alt);
-+ /* moved to em28xx_dvb_init*/
-+ //usb_set_interface(udev, dev->ifnum, dvb_alt);
- rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
- if (rc < 0)
- return rc;
-@@ -1128,8 +1129,9 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
-
- static int em28xx_dvb_init(struct em28xx *dev)
- {
-- int result = 0;
-+ int result = 0, dvb_alt = 0;
- struct em28xx_dvb *dvb;
-+ struct usb_device *udev;
-
- if (dev->is_audio_only) {
- /* Shouldn't initialize IR for this interface */
-@@ -1155,7 +1157,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
- result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
- dev->dvb_xfer_bulk,
- EM28XX_DVB_NUM_BUFS,
-- 512,
-+ 188,
- EM28XX_DVB_BULK_PACKET_MULTIPLIER);
- } else {
- result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
-@@ -1913,7 +1915,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
- 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;
-+ if(dev->ts == PRIMARY_TS) info.addr = 0x64;
-+ else info.addr = 0x67;
- info.platform_data = &si2168_config;
- request_module(info.type);
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
-@@ -1939,7 +1942,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
- #endif
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", I2C_NAME_SIZE);
-- info.addr = 0x60;
-+ if(dev->ts == PRIMARY_TS) info.addr = 0x60;
-+ else info.addr = 0x63;
- info.platform_data = &si2157_config;
- request_module(info.type);
- client = i2c_new_device(adapter, &info);
-@@ -1975,7 +1979,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
- lgdt3306a_config.fe = &dvb->fe[0];
- lgdt3306a_config.i2c_adapter = &adapter;
- strlcpy(info.type, "lgdt3306a", sizeof(info.type));
-- info.addr = 0x59;
-+ if(dev->ts == PRIMARY_TS) info.addr = 0x59;
-+ else info.addr = 0x0e;
- info.platform_data = &lgdt3306a_config;
- request_module(info.type);
- client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
-@@ -2002,7 +2007,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
- #endif
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "si2157", sizeof(info.type));
-- info.addr = 0x60;
-+ if(dev->ts == PRIMARY_TS) info.addr = 0x60;
-+ else info.addr = 0x62;
- info.platform_data = &si2157_config;
- request_module(info.type);
-
-@@ -2045,6 +2051,14 @@ static int em28xx_dvb_init(struct em28xx *dev)
- if (result < 0)
- goto out_free;
-
-+ if (dev->dvb_xfer_bulk) {
-+ dvb_alt = 0;
-+ } else { /* isoc */
-+ dvb_alt = dev->dvb_alt_isoc;
-+ }
-+
-+ udev = interface_to_usbdev(dev->intf);
-+ usb_set_interface(udev, dev->ifnum, dvb_alt);
- dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");
-
- kref_get(&dev->ref);
-diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
-index e8d97d5..132638e 100644
---- a/drivers/media/usb/em28xx/em28xx.h
-+++ b/drivers/media/usb/em28xx/em28xx.h
-@@ -190,7 +190,7 @@
- USB 2.0 spec says bulk packet size is always 512 bytes
- */
- #define EM28XX_BULK_PACKET_MULTIPLIER 384
--#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 384
-+#define EM28XX_DVB_BULK_PACKET_MULTIPLIER 240
-
- #define EM28XX_INTERLACED_DEFAULT 1
-
-@@ -216,6 +216,9 @@
- /* max. number of button state polling addresses */
- #define EM28XX_NUM_BUTTON_ADDRESSES_MAX 5
-
-+#define PRIMARY_TS 0
-+#define SECONDARY_TS 1
-+
- enum em28xx_mode {
- EM28XX_SUSPEND,
- EM28XX_ANALOG_MODE,
-@@ -456,6 +459,7 @@ struct em28xx_board {
- unsigned int mts_firmware:1;
- unsigned int max_range_640_480:1;
- unsigned int has_dvb:1;
-+ unsigned int has_dual_ts:1;
- unsigned int is_webcam:1;
- unsigned int valid:1;
- unsigned int has_ir_i2c:1;
-@@ -620,6 +624,7 @@ struct em28xx {
- unsigned int is_audio_only:1;
- enum em28xx_int_audio_type int_audio_type;
- enum em28xx_usb_audio_type usb_audio_type;
-+ unsigned char name[32];
-
- struct em28xx_board board;
-
-@@ -681,6 +686,8 @@ struct em28xx {
- u8 ifnum; /* number of the assigned usb interface */
- u8 analog_ep_isoc; /* address of isoc endpoint for analog */
- u8 analog_ep_bulk; /* address of bulk endpoint for analog */
-+ u8 dvb_ep_isoc_ts2; /* address of isoc endpoint for DVB TS2*/
-+ u8 dvb_ep_bulk_ts2; /* address of bulk endpoint for DVB TS2*/
- u8 dvb_ep_isoc; /* address of isoc endpoint for DVB */
- u8 dvb_ep_bulk; /* address of bulk endpoint for DVB */
- int alt; /* alternate setting */
-@@ -694,6 +701,8 @@ struct em28xx {
- int dvb_alt_isoc; /* alternate setting for DVB isoc transfers */
- unsigned int dvb_max_pkt_size_isoc; /* isoc max packet size of the
- selected DVB ep at dvb_alt */
-+ unsigned int dvb_max_pkt_size_isoc_ts2; /* isoc max packet size of the
-+ selected DVB ep at dvb_alt */
- unsigned int dvb_xfer_bulk:1; /* use bulk instead of isoc
- transfers for DVB */
- char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
-@@ -725,6 +734,9 @@ struct em28xx {
- struct media_entity input_ent[MAX_EM28XX_INPUT];
- struct media_pad input_pad[MAX_EM28XX_INPUT];
- #endif
-+
-+ struct em28xx *dev_next;
-+ int ts;
- };
-
- #define kref_to_dev(d) container_of(d, struct em28xx, ref)
---
-2.7.4
-
diff --git a/packages/mediacenter/kodi/package.mk b/packages/mediacenter/kodi/package.mk
index 4593d1f4f5..ff26714b0a 100644
--- a/packages/mediacenter/kodi/package.mk
+++ b/packages/mediacenter/kodi/package.mk
@@ -319,6 +319,11 @@ post_makeinstall_target() {
xmlstarlet ed -L --subnode "/addons" -t elem -n "addon" -v "repository.libreelec.tv" $ADDON_MANIFEST
xmlstarlet ed -L --subnode "/addons" -t elem -n "addon" -v "repository.retroplayer.libreelec.tv" $ADDON_MANIFEST
xmlstarlet ed -L --subnode "/addons" -t elem -n "addon" -v "service.libreelec.settings" $ADDON_MANIFEST
+
+ if [ "$DRIVER_ADDONS_SUPPORT" = "yes" ]; then
+ xmlstarlet ed -L --subnode "/addons" -t elem -n "addon" -v "script.program.driverselect" $ADDON_MANIFEST
+ fi
+
if [ "$DEVICE" = "Slice" -o "$DEVICE" = "Slice3" ]; then
xmlstarlet ed -L --subnode "/addons" -t elem -n "addon" -v "service.slice" $ADDON_MANIFEST
fi
diff --git a/packages/virtual/linux-drivers/package.mk b/packages/virtual/linux-drivers/package.mk
index d44273bb6d..05a5130134 100644
--- a/packages/virtual/linux-drivers/package.mk
+++ b/packages/virtual/linux-drivers/package.mk
@@ -20,9 +20,13 @@ PKG_NAME="linux-drivers"
PKG_VERSION=""
PKG_ARCH="any"
PKG_LICENSE="GPL"
-PKG_SITE="http://www.openelec.tv"
+PKG_SITE="https://libreelec.tv"
PKG_URL=""
PKG_DEPENDS_TARGET="toolchain $ADDITIONAL_DRIVERS"
PKG_SECTION="virtual"
PKG_SHORTDESC="linux-drivers: Meta package to install additional drivers"
PKG_LONGDESC="linux-drivers is a Meta package to install additional drivers"
+
+if [ "$DRIVER_ADDONS_SUPPORT" = "yes" ]; then
+ PKG_DEPENDS_TARGET="$PKG_DEPENDS_TARGET $DRIVER_ADDONS driverselect"
+fi
diff --git a/projects/Generic/options b/projects/Generic/options
index ca9c5208a5..56da7426e2 100644
--- a/projects/Generic/options
+++ b/projects/Generic/options
@@ -87,4 +87,12 @@
# for a list of additinoal drivers see packages/linux-drivers
# Space separated list is supported,
# e.g. ADDITIONAL_DRIVERS="DRIVER1 DRIVER2"
- ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS bcm_sta media_build intel_nuc_led"
+ ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS bcm_sta intel_nuc_led"
+
+ # build and install driver addons (yes / no)
+ DRIVER_ADDONS_SUPPORT="yes"
+
+ # driver addons to install:
+ # for a list of additinoal drivers see packages/linux-driver-addons
+ # Space separated list is supported,
+ DRIVER_ADDONS="crazycat digital_devices hauppauge"
diff --git a/projects/RPi/options b/projects/RPi/options
index a2ba616df3..a6d4792431 100644
--- a/projects/RPi/options
+++ b/projects/RPi/options
@@ -160,8 +160,16 @@ fi
# for a list of additinoal drivers see packages/linux-drivers
# Space separated list is supported,
# e.g. ADDITIONAL_DRIVERS="DRIVER1 DRIVER2"
- ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS media_build rpi-cirrus-config"
+ ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS rpi-cirrus-config"
if [ "$DEVICE" = "Slice" -o "$DEVICE" = "Slice3" ]; then
ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS slice-drivers"
fi
+
+ # build and install driver addons (yes / no)
+ DRIVER_ADDONS_SUPPORT="yes"
+
+ # driver addons to install:
+ # for a list of additinoal drivers see packages/linux-driver-addons
+ # Space separated list is supported,
+ DRIVER_ADDONS="crazycat hauppauge"
diff --git a/tools/mkpkg/mkpkg_pvr b/tools/mkpkg/mkpkg_pvr
new file mode 100755
index 0000000000..82bbb54be3
--- /dev/null
+++ b/tools/mkpkg/mkpkg_pvr
@@ -0,0 +1,127 @@
+#!/bin/sh
+################################################################################
+# This file is part of LibreELEC - https://libreelec.tv
+# Copyright (C) 2016-present Team LibreELEC
+#
+# LibreELEC 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.
+#
+# LibreELEC 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 LibreELEC. If not, see .
+################################################################################
+
+# set media_build version you want to use
+if [ -z "$1" ]; then
+ echo "Usage: $0 crazycat | tbs"
+ exit 0
+else
+ MEDIA_BUILD_PROJECT="$1"
+fi
+
+# name of the package
+DVB_MKPKG_FOLDER="$(pwd)"
+
+# crazycat
+if [ "$MEDIA_BUILD_PROJECT" = "crazycat" ]; then
+ MEDIA_BUILD_URL="https://bitbucket.org/CrazyCat/media_build.git"
+ MEDIA_TREE_URL="https://github.com/crazycat69/linux_media.git"
+ MEDIA_TREE_BRANCH="latest"
+ MEDIA_BUILD_NAME="crazycat"
+
+# tbs oss
+elif [ "$MEDIA_BUILD_PROJECT" = "tbs" ]; then
+ MEDIA_BUILD_URL="https://github.com/tbsdtv/media_build.git"
+ MEDIA_TREE_URL="https://github.com/tbsdtv/linux_media.git"
+ MEDIA_TREE_BRANCH="latest"
+ MEDIA_BUILD_NAME="tbs"
+
+# exit
+else
+ echo "exit: no valid project"
+ exit 0
+fi
+
+# remove old files
+echo "removing old sources ..."
+rm -rf $MEDIA_BUILD_NAME*/
+
+################################################################################
+
+# media_build dl
+
+echo "getting media_build sources ..."
+
+if [ ! -d media_build.git ]; then
+ git clone $MEDIA_BUILD_URL media_build/
+fi
+
+#get log
+cd media_build/
+ git pull
+ git checkout $MEDIA_BUILD_HASH
+ GIT_LOG_MEDIA_BUILD=`git log --pretty=oneline -n1`
+
+cd $DVB_MKPKG_FOLDER/
+
+# media_tree dl
+echo "getting sources ..."
+ if [ ! -d linux_media.git ]; then
+ git clone --depth=1 $MEDIA_TREE_URL -b $MEDIA_TREE_BRANCH media_tree
+ fi
+
+#get log
+cd media_tree/
+ git pull
+ GIT_LOG_MEDIA_TREE=`git log --pretty=oneline -n1`
+ GIT_REV=`git log -n1 --pretty=format:"%ad" --date=short`
+
+# hack/workaround for borked upstream kernel/media_build
+# without removing atomisp there a lot additional includes that
+# slowdown build process after modpost from 3min to 6min
+# even if atomisp is disabled via kernel.conf
+ rm -rf drivers/staging/media/atomisp
+ sed -i 's|^.*drivers/staging/media/atomisp.*$||' $DVB_MKPKG_FOLDER/media_tree/drivers/staging/media/Kconfig
+
+cd $DVB_MKPKG_FOLDER/
+
+################################################################################
+
+# collecting files from media_tree
+echo "create media_tree tar"
+cd media_build/linux
+make tar DIR="$DVB_MKPKG_FOLDER/media_tree/"
+
+cd $DVB_MKPKG_FOLDER
+
+# cleanup
+rm -rf media_tree/
+rm -rf media_build/.git/
+
+# rename buildfolder
+mv media_build/ $MEDIA_BUILD_NAME-$GIT_REV/
+
+# log used versions into LE_versions
+echo "package include: $MEDIA_BUILD_NAME\n
+media_build commit: $GIT_LOG_MEDIA_BUILD
+media_build url: $MEDIA_BUILD_URL
+\n
+media_tree commit: $GIT_LOG_MEDIA_TREE
+media_tree url: $MEDIA_TREE_URL
+\n
+package date: $(date +%F_%H:%M:%S)" > $MEDIA_BUILD_NAME-$GIT_REV/LE_versions
+
+################################################################################
+
+# pack sources
+echo "packing sources ..."
+tar cvJf $MEDIA_BUILD_NAME-$GIT_REV.tar.xz $MEDIA_BUILD_NAME-$GIT_REV
+
+echo "remove temporary sourcedir ..."
+rm -rf $MEDIA_BUILD_NAME-$GIT_REV