From 220a9e53eb1877cf9a29df1ed58cab7d4f06f384 Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:29 +0100 Subject: [PATCH 01/11] media_build: remove package --- packages/linux-drivers/media_build/package.mk | 60 -- .../media_build-02-add-to-backports.patch | 17 - ...1056c5564eec8a1b169c6e84ff3.6.114c13.patch | 12 - ...tomer-code-restriction-in-rc6-decode.patch | 28 - .../linux-062-imon_pad_ignore_diagonal.patch | 21 - ...x-203-stb0899_enable_low_symbol_rate.patch | 11 - .../linux-204-lirc_fix_for_4.12.patch | 24 - ...auppauge_dualhd_second_tuner_support.patch | 586 ------------------ projects/Generic/options | 2 +- projects/RPi/options | 2 +- 10 files changed, 2 insertions(+), 761 deletions(-) delete mode 100644 packages/linux-drivers/media_build/package.mk delete mode 100644 packages/linux-drivers/media_build/patches/media_build-02-add-to-backports.patch delete mode 100644 packages/linux-drivers/media_build/sources/backports/linux-054-nuvoton_revert_d7b290a1056c5564eec8a1b169c6e84ff3.6.114c13.patch delete mode 100644 packages/linux-drivers/media_build/sources/backports/linux-057-Removed-MCE-customer-code-restriction-in-rc6-decode.patch delete mode 100644 packages/linux-drivers/media_build/sources/backports/linux-062-imon_pad_ignore_diagonal.patch delete mode 100644 packages/linux-drivers/media_build/sources/backports/linux-203-stb0899_enable_low_symbol_rate.patch delete mode 100644 packages/linux-drivers/media_build/sources/backports/linux-204-lirc_fix_for_4.12.patch delete mode 100644 packages/linux-drivers/media_build/sources/backports/linux-220-hauppauge_dualhd_second_tuner_support.patch diff --git a/packages/linux-drivers/media_build/package.mk b/packages/linux-drivers/media_build/package.mk deleted file mode 100644 index ed3ef6ba34..0000000000 --- a/packages/linux-drivers/media_build/package.mk +++ /dev/null @@ -1,60 +0,0 @@ -################################################################################ -# 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="media_build" -PKG_VERSION="2017-06-20-rpi" -PKG_SHA256="ff30bf1ee9fe342649ad80c9072ab4d37238d05680da850828f6d6c1d6b2e6d4" -PKG_ARCH="any" -PKG_LICENSE="GPL" -PKG_SITE="https://github.com/crazycat69/linux_media" -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" - -pre_make_target() { - export KERNEL_VER=$(get_module_dir) - export LDFLAGS="" -} - -make_target() { - make untar - - # copy config file - if [ "$PROJECT" = Generic ] || [ "$PROJECT" = Virtual ]; then - if [ -f $PKG_DIR/config/generic.config ]; then - cp $PKG_DIR/config/generic.config v4l/.config - fi - else - if [ -f $PKG_DIR/config/usb.config ]; then - cp $PKG_DIR/config/usb.config v4l/.config - fi - fi - - # add menuconfig to edit .config - make VER=$KERNEL_VER SRCDIR=$(kernel_path) -} - -makeinstall_target() { - mkdir -p $INSTALL/$(get_full_module_dir)/updates - find $PKG_BUILD/v4l/ -name \*.ko -exec cp {} $INSTALL/$(get_full_module_dir)/updates \; -} 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/projects/Generic/options b/projects/Generic/options index ca9c5208a5..9364fdb4db 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -87,4 +87,4 @@ # 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" diff --git a/projects/RPi/options b/projects/RPi/options index a2ba616df3..d8dbb7c474 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -160,7 +160,7 @@ 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" From 48c14e212481dee6deb2b6fa64613ba30a55de1b Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:31 +0100 Subject: [PATCH 02/11] dvb-addons: added mkpkg --- tools/mkpkg/mkpkg_pvr | 127 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100755 tools/mkpkg/mkpkg_pvr 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 From 5df12e5de5cb1d81764aaa2536799df1cf62b5a0 Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:32 +0100 Subject: [PATCH 03/11] config/functions: add function install_driver_addon_files --- config/functions | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/config/functions b/config/functions index 91636f7847..e9f2976414 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" From d9ae7fa43820e0f75a66afae485a48e855a30353 Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:32 +0100 Subject: [PATCH 04/11] buildsystem: add DRIVER_ADDONS_SUPPORT --- config/functions | 6 ++++++ config/path | 2 +- packages/virtual/linux-drivers/package.mk | 6 +++++- projects/Generic/options | 8 ++++++++ projects/RPi/options | 8 ++++++++ 5 files changed, 28 insertions(+), 2 deletions(-) diff --git a/config/functions b/config/functions index e9f2976414..3fc07d2ee1 100644 --- a/config/functions +++ b/config/functions @@ -653,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/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 9364fdb4db..41e6871c9e 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -88,3 +88,11 @@ # Space separated list is supported, # e.g. ADDITIONAL_DRIVERS="DRIVER1 DRIVER2" ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS bcm_sta intel_nuc_led" + + # build and install driver addons (yes / no) + DRIVER_ADDONS_SUPPORT="no" + + # driver addons to install: + # for a list of additinoal drivers see packages/linux-driver-addons + # Space separated list is supported, + DRIVER_ADDONS="" diff --git a/projects/RPi/options b/projects/RPi/options index d8dbb7c474..940d7cc660 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -165,3 +165,11 @@ fi if [ "$DEVICE" = "Slice" -o "$DEVICE" = "Slice3" ]; then ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS slice-drivers" fi + + # build and install driver addons (yes / no) + DRIVER_ADDONS_SUPPORT="no" + + # driver addons to install: + # for a list of additinoal drivers see packages/linux-driver-addons + # Space separated list is supported, + DRIVER_ADDONS="" From 540822f224a8e35c4daa65347dd33fa4dd7a4d30 Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:33 +0100 Subject: [PATCH 05/11] driver addons: add driver selector script --- .../addons/script/driverselect/package.mk | 50 +++++++++++++++++++ packages/mediacenter/kodi/package.mk | 5 ++ 2 files changed, 55 insertions(+) create mode 100644 packages/addons/script/driverselect/package.mk 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/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 From b807b84ad02d013d98cda7acba31641276d6f03c Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:34 +0100 Subject: [PATCH 06/11] media_tree: initial package --- .../dvb/depends/media_tree/package.mk | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 packages/linux-driver-addons/dvb/depends/media_tree/package.mk 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..19eababda8 --- /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-11-14-f2ecc3d0787e" +PKG_SHA256="54aaa4cb2ab34804f42410dd461e587ecae36bd808c6e4accb3bcdae8c04579b" +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 +} From 6d1d830638af5b4b25bfbcbb14de3d9f93e3bb82 Mon Sep 17 00:00:00 2001 From: cvh Date: Thu, 14 Dec 2017 12:12:59 +0100 Subject: [PATCH 07/11] driver.dvb: initial hauppauge package --- .../dvb/depends/media_tree/package.mk | 4 +- .../dvb/hauppauge/changelog.txt | 2 + .../dvb/hauppauge/icon/icon.png | Bin 0 -> 23076 bytes .../dvb/hauppauge/package.mk | 51 + ...ver.dvb.hauppauge-01-remove-rmmod.pl.patch | 11 + ...er.dvb.hauppauge-02-add-to-backports.patch | 11 + .../dvb/hauppauge/source/default.py | 17 + .../sources/backports/hauppauge.patch | 3214 +++++++++++++++++ .../sources/backports/temp_revert.patch | 30 + 9 files changed, 3338 insertions(+), 2 deletions(-) create mode 100755 packages/linux-driver-addons/dvb/hauppauge/changelog.txt create mode 100644 packages/linux-driver-addons/dvb/hauppauge/icon/icon.png create mode 100644 packages/linux-driver-addons/dvb/hauppauge/package.mk create mode 100644 packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-01-remove-rmmod.pl.patch create mode 100644 packages/linux-driver-addons/dvb/hauppauge/patches/driver.dvb.hauppauge-02-add-to-backports.patch create mode 100644 packages/linux-driver-addons/dvb/hauppauge/source/default.py create mode 100644 packages/linux-driver-addons/dvb/hauppauge/sources/backports/hauppauge.patch create mode 100644 packages/linux-driver-addons/dvb/hauppauge/sources/backports/temp_revert.patch diff --git a/packages/linux-driver-addons/dvb/depends/media_tree/package.mk b/packages/linux-driver-addons/dvb/depends/media_tree/package.mk index 19eababda8..67f7884d8c 100644 --- a/packages/linux-driver-addons/dvb/depends/media_tree/package.mk +++ b/packages/linux-driver-addons/dvb/depends/media_tree/package.mk @@ -17,8 +17,8 @@ ################################################################################ PKG_NAME="media_tree" -PKG_VERSION="2017-11-14-f2ecc3d0787e" -PKG_SHA256="54aaa4cb2ab34804f42410dd461e587ecae36bd808c6e4accb3bcdae8c04579b" +PKG_VERSION="2017-12-06-b32a2b42f76c" +PKG_SHA256="90a6b5b015bbb5583a6c72880f8b89ed8b3671ca64c713a00ec3467fbb84cdc4" PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="https://git.linuxtv.org/media_tree.git" 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 0000000000000000000000000000000000000000..962157e96e76474e14170551b8bef0ca8607de2f GIT binary patch literal 23076 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 literal 0 HcmV?d00001 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, From bc4d9bb9b5407593052a4656ae5afa3722832762 Mon Sep 17 00:00:00 2001 From: cvh Date: Thu, 14 Dec 2017 12:12:54 +0100 Subject: [PATCH 08/11] driver.dvb: initial digitaldevices package --- .../dvb/digital_devices/changelog.txt | 2 + .../dvb/digital_devices/icon/icon.png | Bin 0 -> 32470 bytes .../dvb/digital_devices/package.mk | 45 ++++++++++++++++++ .../dvb/digital_devices/source/default.py | 17 +++++++ 4 files changed, 64 insertions(+) create mode 100755 packages/linux-driver-addons/dvb/digital_devices/changelog.txt create mode 100644 packages/linux-driver-addons/dvb/digital_devices/icon/icon.png create mode 100644 packages/linux-driver-addons/dvb/digital_devices/package.mk create mode 100644 packages/linux-driver-addons/dvb/digital_devices/source/default.py 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 0000000000000000000000000000000000000000..10c6edc2676b3b90863e49d8ed66f2ecdbf896a2 GIT binary patch literal 32470 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 KpUXO@geCwCxOfi$ literal 0 HcmV?d00001 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 . +################################################################################ From 87e1f557b5cf243c17908f0b94eeb12d89e2a00e Mon Sep 17 00:00:00 2001 From: cvh Date: Thu, 14 Dec 2017 12:12:49 +0100 Subject: [PATCH 09/11] driver.dvb: initial crazycat package --- .../dvb/crazycat/changelog.txt | 2 + .../dvb/crazycat}/config/generic.config | 364 +++-- .../dvb/crazycat}/config/usb.config | 352 ++--- .../dvb/crazycat/icon/icon.png | Bin 0 -> 68596 bytes .../dvb/crazycat/package.mk | 63 + ...ver.dvb.crazycat-01-remove-rmmod.pl.patch} | 0 ...ver.dvb.crazycat-02-add-to-backports.patch | 11 + .../dvb/crazycat/source/default.py | 17 + ...lnbp22_patch_for_more_power_if_rotor.patch | 0 ...ux-220-Xbox-One-DVB-T2-stick-support.patch | 1386 +++++++++++++++++ 10 files changed, 1828 insertions(+), 367 deletions(-) create mode 100755 packages/linux-driver-addons/dvb/crazycat/changelog.txt rename packages/{linux-drivers/media_build => linux-driver-addons/dvb/crazycat}/config/generic.config (94%) rename packages/{linux-drivers/media_build => linux-driver-addons/dvb/crazycat}/config/usb.config (94%) create mode 100644 packages/linux-driver-addons/dvb/crazycat/icon/icon.png create mode 100644 packages/linux-driver-addons/dvb/crazycat/package.mk rename packages/{linux-drivers/media_build/patches/media_build-01-remove-rmmod.pl.patch => linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-01-remove-rmmod.pl.patch} (100%) create mode 100644 packages/linux-driver-addons/dvb/crazycat/patches/driver.dvb.crazycat-02-add-to-backports.patch create mode 100644 packages/linux-driver-addons/dvb/crazycat/source/default.py rename packages/{linux-drivers/media_build => linux-driver-addons/dvb/crazycat}/sources/backports/linux-202-lnbp22_patch_for_more_power_if_rotor.patch (100%) create mode 100644 packages/linux-driver-addons/dvb/crazycat/sources/backports/linux-220-Xbox-One-DVB-T2-stick-support.patch 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 0000000000000000000000000000000000000000..22a6c6a0d90344f27d68561d8d44115debdfe89a GIT binary patch literal 68596 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 literal 0 HcmV?d00001 diff --git a/packages/linux-driver-addons/dvb/crazycat/package.mk b/packages/linux-driver-addons/dvb/crazycat/package.mk new file mode 100644 index 0000000000..ebbb4e42f6 --- /dev/null +++ b/packages/linux-driver-addons/dvb/crazycat/package.mk @@ -0,0 +1,63 @@ +################################################################################ +# 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="crazycat" +PKG_VERSION="2017-11-13" +PKG_SHA256="14d951eb8d40cee40d601d7c737bca07171d8b4f201d63d5e70a24c4841f9d73" +PKG_ARCH="any" +PKG_LICENSE="GPL" +PKG_SITE="https://github.com/crazycat69/linux_media" +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.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) + export LDFLAGS="" +} + +make_target() { + make untar + + # copy config file + if [ "$PROJECT" = Generic ]; then + if [ -f $PKG_DIR/config/generic.config ]; then + cp $PKG_DIR/config/generic.config v4l/.config + fi + else + if [ -f $PKG_DIR/config/usb.config ]; then + cp $PKG_DIR/config/usb.config v4l/.config + fi + fi + + # add menuconfig to edit .config + make VER=$KERNEL_VER SRCDIR=$(kernel_path) +} + +makeinstall_target() { + 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 + From 8b4322df6aa853b862369c8b51a048944df083b1 Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:37 +0100 Subject: [PATCH 10/11] driver addons: enable for RPi --- projects/RPi/options | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/RPi/options b/projects/RPi/options index 940d7cc660..a6d4792431 100644 --- a/projects/RPi/options +++ b/projects/RPi/options @@ -167,9 +167,9 @@ fi fi # build and install driver addons (yes / no) - DRIVER_ADDONS_SUPPORT="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="" + DRIVER_ADDONS="crazycat hauppauge" From 5f3b67d2398ee9b3486ef3df50322d526e96d443 Mon Sep 17 00:00:00 2001 From: cvh Date: Sun, 10 Dec 2017 18:50:38 +0100 Subject: [PATCH 11/11] driver addons: enable for Generic --- projects/Generic/options | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/projects/Generic/options b/projects/Generic/options index 41e6871c9e..56da7426e2 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -90,9 +90,9 @@ ADDITIONAL_DRIVERS="$ADDITIONAL_DRIVERS bcm_sta intel_nuc_led" # build and install driver addons (yes / no) - DRIVER_ADDONS_SUPPORT="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="" + DRIVER_ADDONS="crazycat digital_devices hauppauge"