From 6d1d830638af5b4b25bfbcbb14de3d9f93e3bb82 Mon Sep 17 00:00:00 2001 From: cvh Date: Thu, 14 Dec 2017 12:12:59 +0100 Subject: [PATCH] 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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%0DSdYn5%nglyP2bEUWPY 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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,