[PATCH v2 2/5] media: dvb_frontend: add DVB-S2X rolloff factors
From: Daniel Scheller Add 15%, 10% and 5% DVB-S2X rolloff factors. Also fix roloff typos. Signed-off-by: Daniel Scheller --- Documentation/media/frontend.h.rst.exceptions | 3 +++ drivers/media/dvb-core/dvb_frontend.c | 9 + include/uapi/linux/dvb/frontend.h | 16 +++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Documentation/media/frontend.h.rst.exceptions b/Documentation/media/frontend.h.rst.exceptions index ae1148be0a39..c1643ce93426 100644 --- a/Documentation/media/frontend.h.rst.exceptions +++ b/Documentation/media/frontend.h.rst.exceptions @@ -167,6 +167,9 @@ ignore symbol ROLLOFF_35 ignore symbol ROLLOFF_20 ignore symbol ROLLOFF_25 ignore symbol ROLLOFF_AUTO +ignore symbol ROLLOFF_15 +ignore symbol ROLLOFF_10 +ignore symbol ROLLOFF_5 ignore symbol INVERSION_ON ignore symbol INVERSION_OFF diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 722b86a43497..e5105c1783b8 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2183,6 +2183,15 @@ static int dtv_set_frontend(struct dvb_frontend *fe) break; case SYS_DVBS2: switch (c->rolloff) { + case ROLLOFF_5: + rolloff = 105; + break; + case ROLLOFF_10: + rolloff = 110; + break; + case ROLLOFF_15: + rolloff = 115; + break; case ROLLOFF_20: rolloff = 120; break; diff --git a/include/uapi/linux/dvb/frontend.h b/include/uapi/linux/dvb/frontend.h index 227268a657cd..8bf1c63627a2 100644 --- a/include/uapi/linux/dvb/frontend.h +++ b/include/uapi/linux/dvb/frontend.h @@ -580,20 +580,26 @@ enum fe_pilot { /** * enum fe_rolloff - Rolloff factor - * @ROLLOFF_35:Roloff factor: α=35% - * @ROLLOFF_20:Roloff factor: α=20% - * @ROLLOFF_25:Roloff factor: α=25% - * @ROLLOFF_AUTO: Auto-detect the roloff factor. + * @ROLLOFF_35:Rolloff factor: α=35% + * @ROLLOFF_20:Rolloff factor: α=20% + * @ROLLOFF_25:Rolloff factor: α=25% + * @ROLLOFF_AUTO: Auto-detect the rolloff factor. + * @ROLLOFF_15:Rolloff factor: α=15% + * @ROLLOFF_10:Rolloff factor: α=10% + * @ROLLOFF_5: Rolloff factor: α=5% * * .. note: * - *Roloff factor of 35% is implied on DVB-S. On DVB-S2, it is default. + *Rolloff factor of 35% is implied on DVB-S. On DVB-S2, it is default. */ enum fe_rolloff { ROLLOFF_35, ROLLOFF_20, ROLLOFF_25, ROLLOFF_AUTO, + ROLLOFF_15, + ROLLOFF_10, + ROLLOFF_5, }; /** -- 2.13.6
[PATCH v2 1/5] media: dvb_frontend: add FEC modes, S2X modulations and 64K transmission
From: Daniel Scheller Add 1/4 and 1/3 FEC ratios, 64/128/256-APSK S2X modulations and 64K transmission mode. Update relevant doc items aswell. Signed-off-by: Daniel Scheller --- Documentation/media/frontend.h.rst.exceptions | 6 ++ include/uapi/linux/dvb/frontend.h | 13 + 2 files changed, 19 insertions(+) diff --git a/Documentation/media/frontend.h.rst.exceptions b/Documentation/media/frontend.h.rst.exceptions index f7c4df620a52..ae1148be0a39 100644 --- a/Documentation/media/frontend.h.rst.exceptions +++ b/Documentation/media/frontend.h.rst.exceptions @@ -84,6 +84,9 @@ ignore symbol APSK_16 ignore symbol APSK_32 ignore symbol DQPSK ignore symbol QAM_4_NR +ignore symbol APSK_64 +ignore symbol APSK_128 +ignore symbol APSK_256 ignore symbol SEC_VOLTAGE_13 ignore symbol SEC_VOLTAGE_18 @@ -117,6 +120,8 @@ ignore symbol FEC_AUTO ignore symbol FEC_3_5 ignore symbol FEC_9_10 ignore symbol FEC_2_5 +ignore symbol FEC_1_4 +ignore symbol FEC_1_3 ignore symbol TRANSMISSION_MODE_AUTO ignore symbol TRANSMISSION_MODE_1K @@ -129,6 +134,7 @@ ignore symbol TRANSMISSION_MODE_C1 ignore symbol TRANSMISSION_MODE_C3780 ignore symbol TRANSMISSION_MODE_2K ignore symbol TRANSMISSION_MODE_8K +ignore symbol TRANSMISSION_MODE_64K ignore symbol GUARD_INTERVAL_AUTO ignore symbol GUARD_INTERVAL_1_128 diff --git a/include/uapi/linux/dvb/frontend.h b/include/uapi/linux/dvb/frontend.h index 4f9b4551c534..227268a657cd 100644 --- a/include/uapi/linux/dvb/frontend.h +++ b/include/uapi/linux/dvb/frontend.h @@ -296,6 +296,8 @@ enum fe_spectral_inversion { * @FEC_3_5: Forward Error Correction Code 3/5 * @FEC_9_10: Forward Error Correction Code 9/10 * @FEC_2_5: Forward Error Correction Code 2/5 + * @FEC_1_4: Forward Error Correction Code 1/4 + * @FEC_1_3: Forward Error Correction Code 1/3 * * Please note that not all FEC types are supported by a given standard. */ @@ -313,6 +315,8 @@ enum fe_code_rate { FEC_3_5, FEC_9_10, FEC_2_5, + FEC_1_4, + FEC_1_3, }; /** @@ -331,6 +335,9 @@ enum fe_code_rate { * @APSK_32: 32-APSK modulation * @DQPSK: DQPSK modulation * @QAM_4_NR: 4-QAM-NR modulation + * @APSK_64: 64-APSK modulation + * @APSK_128: 128-APSK modulation + * @APSK_256: 256-APSK modulation * * Please note that not all modulations are supported by a given standard. * @@ -350,6 +357,9 @@ enum fe_modulation { APSK_32, DQPSK, QAM_4_NR, + APSK_64, + APSK_128, + APSK_256, }; /** @@ -374,6 +384,8 @@ enum fe_modulation { * Single Carrier (C=1) transmission mode (DTMB only) * @TRANSMISSION_MODE_C3780: * Multi Carrier (C=3780) transmission mode (DTMB only) + * @TRANSMISSION_MODE_64K: + * Transmission mode 64K * * Please note that not all transmission modes are supported by a given * standard. @@ -388,6 +400,7 @@ enum fe_transmit_mode { TRANSMISSION_MODE_32K, TRANSMISSION_MODE_C1, TRANSMISSION_MODE_C3780, + TRANSMISSION_MODE_64K, }; /** -- 2.13.6
[PATCH v2 0/5] Add FEC rates, S2X params and 64K transmission
From: Daniel Scheller dddvb brings a few additional FEC rates (1/4 and 1/3), 64/128/256APSK modulations and more rolloff factors (DVB-S2X), and 64K transmission mode (DVB-T2). These rather trivial patches bring them to mainline, and puts these missing bits into the stv0910's get_frontend() callback (FEC 1/4 and 1/3 are handled throughout the rest of the demod driver already). In addition (as suggestion from Richard Scobie), the stv0910 driver now reports it's active delivery system. Changes from v1 to v2: - DVB-S2X rolloff factors and reporting - report of the active delivery system in stv0910:get_frontend() Daniel Scheller (5): media: dvb_frontend: add FEC modes, S2X modulations and 64K transmission media: dvb_frontend: add DVB-S2X rolloff factors media: dvb-frontends/stv0910: report FEC 1/4 and 1/3 in get_frontend() media: dvb-frontends/stv0910: report S2 rolloff in get_frontend() media: dvb-frontends/stv0910: report active delsys in get_frontend() Documentation/media/frontend.h.rst.exceptions | 9 + drivers/media/dvb-core/dvb_frontend.c | 9 + drivers/media/dvb-frontends/stv0910.c | 16 ++- include/uapi/linux/dvb/frontend.h | 29 ++- 4 files changed, 53 insertions(+), 10 deletions(-) -- 2.13.6
[PATCH v2 4/5] media: dvb-frontends/stv0910: report S2 rolloff in get_frontend()
From: Daniel Scheller Report the currently used S2 rolloff factor in get_frontend(). For cosmetic reasons, also change all feroll_off occurences to fe_rolloff. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0910.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index de132a85e537..7ab014cec56c 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -113,7 +113,7 @@ struct stv { enum fe_stv0910_mod_cod mod_cod; enum dvbs2_fectype fectype; u32 pilots; - enum fe_stv0910_roll_off feroll_off; + enum fe_stv0910_roll_off fe_rolloff; int is_standard_broadcast; int is_vcm; @@ -541,7 +541,7 @@ static int get_signal_parameters(struct stv *state) } state->is_vcm = 0; state->is_standard_broadcast = 1; - state->feroll_off = FE_SAT_35; + state->fe_rolloff = FE_SAT_35; } return 0; } @@ -1300,14 +1300,14 @@ static int manage_matype_info(struct stv *state) read_regs(state, RSTV0910_P2_MATSTR1 + state->regoff, bbheader, 2); - state->feroll_off = + state->fe_rolloff = (enum fe_stv0910_roll_off)(bbheader[0] & 0x03); state->is_vcm = (bbheader[0] & 0x10) == 0; state->is_standard_broadcast = (bbheader[0] & 0xFC) == 0xF0; } else if (state->receive_mode == RCVMODE_DVBS) { state->is_vcm = 0; state->is_standard_broadcast = 1; - state->feroll_off = FE_SAT_35; + state->fe_rolloff = FE_SAT_35; } return 0; } @@ -1571,11 +1571,15 @@ static int get_frontend(struct dvb_frontend *fe, FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10 }; + const enum fe_rolloff ro2ro[4] = { + ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_15, + }; read_reg(state, RSTV0910_P2_DMDMODCOD + state->regoff, &tmp); mc = ((tmp & 0x7c) >> 2); p->pilot = (tmp & 0x01) ? PILOT_ON : PILOT_OFF; p->modulation = modcod2mod[mc]; p->fec_inner = modcod2fec[mc]; + p->rolloff = ro2ro[state->fe_rolloff]; } else if (state->receive_mode == RCVMODE_DVBS) { read_reg(state, RSTV0910_P2_VITCURPUN + state->regoff, &tmp); switch (tmp & 0x1F) { -- 2.13.6
[PATCH v2 5/5] media: dvb-frontends/stv0910: report active delsys in get_frontend()
From: Daniel Scheller Report the active delivery system based on the receive_mode state of the demodulator. Suggested-by: Richard Scobie Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0910.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index 7ab014cec56c..6e6a70ad7354 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -1580,6 +1580,7 @@ static int get_frontend(struct dvb_frontend *fe, p->modulation = modcod2mod[mc]; p->fec_inner = modcod2fec[mc]; p->rolloff = ro2ro[state->fe_rolloff]; + p->delivery_system = SYS_DVBS2; } else if (state->receive_mode == RCVMODE_DVBS) { read_reg(state, RSTV0910_P2_VITCURPUN + state->regoff, &tmp); switch (tmp & 0x1F) { @@ -1603,6 +1604,7 @@ static int get_frontend(struct dvb_frontend *fe, break; } p->rolloff = ROLLOFF_35; + p->delivery_system = SYS_DVBS; } if (state->receive_mode != RCVMODE_NONE) { -- 2.13.6
[PATCH v2 3/5] media: dvb-frontends/stv0910: report FEC 1/4 and 1/3 in get_frontend()
From: Daniel Scheller The first two missing FECs in the modcod2fec fe_code_rate table were 1/4 and 1/3. Add them as they're now defined by the API. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0910.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index a2f7c0c1587f..de132a85e537 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -1562,7 +1562,7 @@ static int get_frontend(struct dvb_frontend *fe, APSK_32, }; const enum fe_code_rate modcod2fec[0x20] = { - FEC_NONE, FEC_NONE, FEC_NONE, FEC_2_5, + FEC_NONE, FEC_1_4, FEC_1_3, FEC_2_5, FEC_1_2, FEC_3_5, FEC_2_3, FEC_3_4, FEC_4_5, FEC_5_6, FEC_8_9, FEC_9_10, FEC_3_5, FEC_2_3, FEC_3_4, FEC_5_6, -- 2.13.6
[PATCH 7/7] [media] MAINTAINERS: add entry for cxd2099
From: Jasmin Jessich The cxd2099 driver is now maintained and being taken care of by * Jasmin Jessich Signed-off-by: Jasmin Jessich --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aee793bff977..c3b689e2583e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8540,6 +8540,14 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: drivers/media/dvb-frontends/ascot2e* +MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS +M: Jasmin Jessich +L: linux-media@vger.kernel.org +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/cxd2099* + MEDIA DRIVERS FOR CXD2841ER M: Sergey Kozlov M: Abylay Ospan -- 2.13.6
[PATCH 5/7] [media] staging/cxd2099: remove remainders from old attach way
From: Daniel Scheller As all drivers using the cxd2099 are converted to handle attach/detach the generic I2C client way, the static inline cxd2099_attach isn't required anymore. Thus cleanup cxd2099.h from the remainders, the adr struct member isn't used anymore aswell. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/staging/media/cxd2099/cxd2099.h | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/staging/media/cxd2099/cxd2099.h index 679e87512799..8fa45a4c615a 100644 --- a/drivers/staging/media/cxd2099/cxd2099.h +++ b/drivers/staging/media/cxd2099/cxd2099.h @@ -20,7 +20,6 @@ struct cxd2099_cfg { u32 bitrate; - u8 adr; u8 polarity; u8 clock_mode; @@ -30,13 +29,4 @@ struct cxd2099_cfg { struct dvb_ca_en50221 **en; }; -/* TODO: remove when done */ -static inline struct -dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv, - struct i2c_adapter *i2c) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - #endif -- 2.13.6
[PATCH 6/7] [media] cxd2099: move driver out of staging into dvb-frontends
From: Daniel Scheller According to the TODO file, this driver only landed in staging because of the way device nodes and data transfers are handled. Besides that this way (use of secX devices) has become sort of standard to date (ie. VDR supports this literally since ages via the ddci plugin, TVHeadend received this functionality lately, and minisatip being currently worked on regarding this), most importantly this I2C client only driver isn't even responsible for setting up device nodes, not for handling data transfer and so on, but only serves as interface for the dvb_ca_en50221 subsystem, just like every other DVB card out in the wild, with hard-wired or such flexible CA interfaces. And, it would even work with cards having the cxd2099 controller hard-wired. Also, this driver received quite some love and even is a proper I2C client driver by now. So, as this driver acts as a EN50221 frontend device, move it to dvb-frontends. There is no need to keep it buried in staging. This commit also updates all affected Kconfig and Makefile's, and adds MEDIA_AUTOSELECT depends to ddbridge and ngene. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/dvb-frontends/Kconfig | 12 drivers/media/dvb-frontends/Makefile | 1 + .../{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.c | 0 .../{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.h | 0 drivers/media/pci/ddbridge/Kconfig | 1 + drivers/media/pci/ddbridge/Makefile | 3 --- drivers/media/pci/ngene/Kconfig | 1 + drivers/media/pci/ngene/Makefile | 3 --- drivers/staging/media/Kconfig| 2 -- drivers/staging/media/Makefile | 1 - drivers/staging/media/cxd2099/Kconfig| 12 drivers/staging/media/cxd2099/Makefile | 4 drivers/staging/media/cxd2099/TODO | 12 13 files changed, 15 insertions(+), 37 deletions(-) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.c (100%) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.h (100%) delete mode 100644 drivers/staging/media/cxd2099/Kconfig delete mode 100644 drivers/staging/media/cxd2099/Makefile delete mode 100644 drivers/staging/media/cxd2099/TODO diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index d17722eb4456..ca8c7ed079dd 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -904,6 +904,18 @@ config DVB_HELENE help Say Y when you want to support this frontend. +comment "Common Interface (EN50221) controller drivers" + depends on DVB_CORE + +config DVB_CXD2099 + tristate "CXD2099AR Common Interface driver" + depends on DVB_CORE && I2C + ---help--- + A driver for the CI controller currently found mostly on + Digital Devices DuoFlex CI (single) addon modules. + + Say Y when you want to support these devices. + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 4be59fed4536..abbd76ede540 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -129,3 +129,4 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o obj-$(CONFIG_DVB_HELENE) += helene.o obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o +obj-$(CONFIG_DVB_CXD2099) += cxd2099.o diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c similarity index 100% rename from drivers/staging/media/cxd2099/cxd2099.c rename to drivers/media/dvb-frontends/cxd2099.c diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h similarity index 100% rename from drivers/staging/media/cxd2099/cxd2099.h rename to drivers/media/dvb-frontends/cxd2099.h diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index f43d0b83fc0c..a422dde2f34a 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -13,6 +13,7 @@ config DVB_DDBRIDGE select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index f58fdec50eab..745b37d07558 100644 --- a/drivers/media/pci/ddbridge/Makefile +++
[PATCH 3/7] [media] ddbridge: adapt cxd2099 attach to new i2c_client way
From: Daniel Scheller Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/pci/ddbridge/ddbridge-ci.c | 62 +--- drivers/media/pci/ddbridge/ddbridge.h| 1 + 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index ed19890710d6..6585ef54ac22 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -172,6 +172,7 @@ static void ci_attach(struct ddb_port *port) memcpy(&ci->en, &en_templ, sizeof(en_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; } @@ -304,6 +305,7 @@ static void ci_xo2_attach(struct ddb_port *port) memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; ci->port->creg = 0; @@ -311,20 +313,58 @@ static void ci_xo2_attach(struct ddb_port *port) write_creg(ci, 0x08, 0x08); } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 72000, - .adr = 0x40, .polarity = 1, .clock_mode = 1, .max_i2c = 512, }; +static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) +{ + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.bitrate = bitrate; + cxd_cfg.en = &port->en; + + request_module(board_info.type); + + client = i2c_new_device(&port->i2c->adap, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!port->en) + goto err_i2c; + + port->dvb[0].i2c_client[0] = client; + port->en_freedata = 0; + return 0; + +err_i2c: + i2c_unregister_device(client); +err_ret: + dev_err(port->dev->dev, "CXD2099AR attach failed\n"); + return -ENODEV; +} + int ddb_ci_attach(struct ddb_port *port, u32 bitrate) { + int ret; + switch (port->type) { case DDB_CI_EXTERNAL_SONY: - cxd_cfg.bitrate = bitrate; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + ret = ci_cxd2099_attach(port, bitrate); + if (ret) + return -ENODEV; break; case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: @@ -345,11 +385,23 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { + struct i2c_client *client; + if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - kfree(port->en->data); + + client = port->dvb[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* free alloc'ed memory if needed */ + if (port->en_freedata) + kfree(port->en->data); + port->en = NULL; } } diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 095457737bc1..f223dc6c9963 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -276,6 +276,7 @@ struct ddb_port { struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + u8 en_freedata; struct ddb_dvb dvb[2]; u32gap; u32obr; -- 2.13.6
[PATCH 4/7] [media] ngene: adapt cxd2099 attach to the new i2c_client way
From: Daniel Scheller Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/pci/ngene/ngene-core.c | 41 drivers/media/pci/ngene/ngene.h | 1 + 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 8c92cb7f7e72..80db777cb7ec 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1562,9 +1562,8 @@ static int init_channels(struct ngene *dev) return 0; } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 62000, - .adr = 0x40, .polarity = 0, .clock_mode = 0, }; @@ -1572,18 +1571,52 @@ static struct cxd2099_cfg cxd_cfg = { static void cxd_attach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.en = &ci->en; + + request_module(board_info.type); + + client = i2c_new_device(&dev->channel[0].i2c_adapter, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!ci->en) + goto err_i2c; - ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); ci->dev = dev; + dev->channel[0].i2c_client[0] = client; + return; + +err_i2c: + i2c_unregister_device(client); +err_ret: + printk(KERN_ERR DEVICE_NAME ": CXD2099AR attach failed\n"); return; } static void cxd_detach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; + struct i2c_client *client; dvb_ca_en50221_release(ci->en); - kfree(ci->en); + + client = dev->channel[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + ci->en = NULL; } diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 02dbd18f92d0..caf8602c7459 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -630,6 +630,7 @@ struct ngene_vopen { struct ngene_channel { struct device device; struct i2c_adapteri2c_adapter; + struct i2c_client*i2c_client[1]; struct ngene *dev; int number; -- 2.13.6
[PATCH 1/7] [media] ddbridge/ci: further deduplicate code/logic in ddb_ci_attach()
From: Daniel Scheller Deduplicate the checks for a valid ptr in port->en, and also handle the default case to also catch eventually yet unsupported CI hardware. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-ci.c | 12 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 5828111487b0..ed19890710d6 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -325,24 +325,20 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) case DDB_CI_EXTERNAL_SONY: cxd_cfg.bitrate = bitrate; port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) - return -ENODEV; break; - case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: ci_xo2_attach(port); - if (!port->en) - return -ENODEV; break; - case DDB_CI_INTERNAL: ci_attach(port); - if (!port->en) - return -ENODEV; break; + default: + return -ENODEV; } + if (!port->en) + return -ENODEV; dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); return 0; } -- 2.13.6
[PATCH 0/7] cxd2099: convert to regmap API and move out of staging
From: Daniel Scheller Patch series done by Jasmin and me. This patch series, besides one little cosmetic fix in ddbridge, converts the cxd2099 CI controller driver to the regmap API and thus makes it a proper I2C client driver. This not only moves it away from the legacy/ "proprietary" DVB attach way of using I2C drivers, but also adds a cleanup function through the I2C remove callback (such functionality is seemingly currently missing from the DVB EN50221 API). Both ddbridge and ngene (as users of the driver) are updated separately. No regressions were spotted when used in conjuntion with VDR's and TVHeadend's CI support. In addition, this series moves the cxd2099 driver out of staging right into dvb-frontends/ as it serves as a DVB (EN50221) frontend driver. What's written in the TODO file in the staging dir simply doesn't apply to the driver (see the commit message of that specific patch for details) and it got quite polished up lately, so it's just inappropriate to keep it in staging. Lastly, Jasmin opted to take over maintainership of the driver, so the last patch adds her into the MAINTAINERS file for the cxd2099 driver. Please pick this series up in this (upcoming) merge window so it'll be part of the 4.17 kernel release. Daniel Scheller (6): [media] ddbridge/ci: further deduplicate code/logic in ddb_ci_attach() [media] staging/cxd2099: convert to regmap API [media] ddbridge: adapt cxd2099 attach to new i2c_client way [media] ngene: adapt cxd2099 attach to the new i2c_client way [media] staging/cxd2099: remove remainders from old attach way [media] cxd2099: move driver out of staging into dvb-frontends Jasmin Jessich (1): [media] MAINTAINERS: add entry for cxd2099 MAINTAINERS| 8 + drivers/media/dvb-frontends/Kconfig| 12 ++ drivers/media/dvb-frontends/Makefile | 1 + .../cxd2099 => media/dvb-frontends}/cxd2099.c | 209 ++--- .../cxd2099 => media/dvb-frontends}/cxd2099.h | 19 +- drivers/media/pci/ddbridge/Kconfig | 1 + drivers/media/pci/ddbridge/Makefile| 3 - drivers/media/pci/ddbridge/ddbridge-ci.c | 72 +-- drivers/media/pci/ddbridge/ddbridge.h | 1 + drivers/media/pci/ngene/Kconfig| 1 + drivers/media/pci/ngene/Makefile | 3 - drivers/media/pci/ngene/ngene-core.c | 41 +++- drivers/media/pci/ngene/ngene.h| 1 + drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/cxd2099/Kconfig | 12 -- drivers/staging/media/cxd2099/Makefile | 4 - drivers/staging/media/cxd2099/TODO | 12 -- 18 files changed, 229 insertions(+), 174 deletions(-) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.c (78%) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.h (62%) delete mode 100644 drivers/staging/media/cxd2099/Kconfig delete mode 100644 drivers/staging/media/cxd2099/Makefile delete mode 100644 drivers/staging/media/cxd2099/TODO -- 2.13.6
[PATCH 2/7] [media] staging/cxd2099: convert to regmap API
From: Daniel Scheller Convert the cxd2099 driver to use regmap for I2C accesses, removing all own i2c_*() functions. With that, make the driver a proper I2C client driver. This also adds the benefit of having a proper cleanup function (cxd2099_remove() in this case) that takes care of resource cleanup upon I2C client deregistration. At this point, keep the static inline declared cxd2099_attach() function so that drivers using the legacy/proprietary style attach way still compile, albeit lacking the cxd2099 driver functionality. This is taken care of in the next two patches. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/staging/media/cxd2099/cxd2099.c | 209 drivers/staging/media/cxd2099/cxd2099.h | 11 +- 2 files changed, 108 insertions(+), 112 deletions(-) diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c index dc9cbd8f2104..c0a5849b76bb 100644 --- a/drivers/staging/media/cxd2099/cxd2099.c +++ b/drivers/staging/media/cxd2099/cxd2099.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,8 +34,9 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); struct cxd { struct dvb_ca_en50221 en; - struct i2c_adapter *i2c; struct cxd2099_cfg cfg; + struct i2c_client *client; + struct regmap *regmap; u8 regs[0x23]; u8 lastaddress; @@ -56,69 +58,12 @@ struct cxd { u8 wbuf[1028]; }; -static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, -u8 reg, u8 data) -{ - u8 m[2] = {reg, data}; - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - dev_err(&adapter->dev, - "Failed to write to I2C register %02x@%02x!\n", - reg, adr); - return -1; - } - return 0; -} - -static int i2c_write(struct i2c_adapter *adapter, u8 adr, -u8 *data, u16 len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - dev_err(&adapter->dev, "Failed to write to I2C!\n"); - return -1; - } - return 0; -} - -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *val) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - dev_err(&adapter->dev, "error in %s()\n", __func__); - return -1; - } - return 0; -} - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *data, u16 n) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = data, .len = n} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - dev_err(&adapter->dev, "error in %s()\n", __func__); - return -1; - } - return 0; -} - static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) { int status = 0; if (ci->lastaddress != adr) - status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr); + status = regmap_write(ci->regmap, 0, adr); if (!status) { ci->lastaddress = adr; @@ -127,7 +72,7 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) len = ci->cfg.max_i2c; - status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len); + status = regmap_raw_read(ci->regmap, 1, data, len); if (status) return status; data += len; @@ -145,64 +90,66 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val) static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) { int status; - u8 addr[3] = {2, address & 0xff, address >> 8}; + u8 addr[2] = {address & 0xff, address >> 8}; - status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3); + status = regmap_raw_write(ci->regmap, 2, addr, 2); if (!status) - status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n); + status = regmap_raw_read(ci->regmap, 3, data, n); return s
[PATCH] [media] dvb-frontends/stv0910: rework and fix DiSEqC send
From: Daniel Scheller Rework both DiSEqC send functions (send_master_cmd() and send_burst()) to utilise the new SET_REG() and SET_FIELD() macros. Esp. due to SET_FIELD(), this makes sure that not all bits (with unrelated purposes) are always rewritten, but only those needed for sending DiSEqC commands. In send_burst(), this makes sure that DISEQC_MODE isn't changed from 3 to 2 inbetween when sending SEC_MINI_A. Also, change both functions to write DISEQC_MODE first before setting DIS_PRECHARGE. This makes diseqc control work more reliable for "fullblown" DiSEqC strings in VDR's diseqc.conf in combination with certain multiswitches. Fixes: 448461af0e19 ("media: dvb-frontends/stv0910: implement diseqc_send_burst") Reported-by: Helmut Auer Cc: Ralph Metzler Signed-off-by: Daniel Scheller Tested-by: Helmut Auer Tested-by: Richard Scobie Tested-by: Dietmar Spingler --- drivers/media/dvb-frontends/stv0910.c | 19 ++- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index a2f7c0c1587f..52355c14fd64 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -1673,15 +1673,15 @@ static int send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct stv *state = fe->demodulator_priv; - u16 offs = state->nr ? 0x40 : 0; int i; - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + SET_FIELD(DISEQC_MODE, 2); + SET_FIELD(DIS_PRECHARGE, 1); for (i = 0; i < cmd->msg_len; i++) { wait_dis(state, 0x40, 0x00); - write_reg(state, RSTV0910_P1_DISTXFIFO + offs, cmd->msg[i]); + SET_REG(DISTXFIFO, cmd->msg[i]); } - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + SET_FIELD(DIS_PRECHARGE, 0); wait_dis(state, 0x20, 0x20); return 0; } @@ -1689,19 +1689,20 @@ static int send_master_cmd(struct dvb_frontend *fe, static int send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst) { struct stv *state = fe->demodulator_priv; - u16 offs = state->nr ? 0x40 : 0; u8 value; if (burst == SEC_MINI_A) { - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3F); + SET_FIELD(DISEQC_MODE, 3); value = 0x00; } else { - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3E); + SET_FIELD(DISEQC_MODE, 2); value = 0xFF; } + + SET_FIELD(DIS_PRECHARGE, 1); wait_dis(state, 0x40, 0x00); - write_reg(state, RSTV0910_P1_DISTXFIFO + offs, value); - write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); + SET_REG(DISTXFIFO, value); + SET_FIELD(DIS_PRECHARGE, 0); wait_dis(state, 0x20, 0x20); return 0; -- 2.13.6
[PATCH v2 0/7] cxd2099: convert to regmap API and move out of staging
From: Daniel Scheller Patch series done by Jasmin and me. This patch series, besides one little cosmetic fix in ddbridge, converts the cxd2099 CI controller driver to the regmap API and thus makes it a proper I2C client driver. This not only moves it away from the legacy/ "proprietary" DVB attach way of using I2C drivers, but also adds a cleanup function through the I2C remove callback (such functionality is seemingly currently missing from the DVB EN50221 API). Both ddbridge and ngene (as users of the driver) are updated separately. No regressions were spotted when used in conjuntion with VDR's and TVHeadend's CI support. Testing with an ngene card revealed that I2C_FUNC_I2C needs to be reported in .functionality, else things will fail starting at the CAM detection. In addition, this series moves the cxd2099 driver out of staging right into dvb-frontends/ as it serves as a DVB (EN50221) frontend driver. What's written in the TODO file in the staging dir simply doesn't apply to the driver (see the commit message of that specific patch for details) and it got quite polished up lately, so it's just inappropriate to keep it in staging. Lastly, Jasmin opted to take over maintainership of the driver, so the last patch adds her into the MAINTAINERS file for the cxd2099 driver. Please pick this series up in this merge window so it'll be part of the 4.17 kernel release. Changes since v1: - ngene's I2C interface also reports I2C_FUNC_I2C in .functionality Daniel Scheller (6): [media] ddbridge/ci: further deduplicate code/logic in ddb_ci_attach() [media] staging/cxd2099: convert to regmap API [media] ddbridge: adapt cxd2099 attach to new i2c_client way [media] ngene: adapt cxd2099 attach to the new i2c_client way [media] staging/cxd2099: remove remainders from old attach way [media] cxd2099: move driver out of staging into dvb-frontends Jasmin Jessich (1): [media] MAINTAINERS: add entry for cxd2099 MAINTAINERS| 8 + drivers/media/dvb-frontends/Kconfig| 12 ++ drivers/media/dvb-frontends/Makefile | 1 + .../cxd2099 => media/dvb-frontends}/cxd2099.c | 209 ++--- .../cxd2099 => media/dvb-frontends}/cxd2099.h | 19 +- drivers/media/pci/ddbridge/Kconfig | 1 + drivers/media/pci/ddbridge/Makefile| 3 - drivers/media/pci/ddbridge/ddbridge-ci.c | 72 +-- drivers/media/pci/ddbridge/ddbridge.h | 1 + drivers/media/pci/ngene/Kconfig| 1 + drivers/media/pci/ngene/Makefile | 3 - drivers/media/pci/ngene/ngene-core.c | 41 +++- drivers/media/pci/ngene/ngene-i2c.c| 2 +- drivers/media/pci/ngene/ngene.h| 1 + drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/cxd2099/Kconfig | 12 -- drivers/staging/media/cxd2099/Makefile | 4 - drivers/staging/media/cxd2099/TODO | 12 -- 19 files changed, 230 insertions(+), 175 deletions(-) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.c (78%) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.h (62%) delete mode 100644 drivers/staging/media/cxd2099/Kconfig delete mode 100644 drivers/staging/media/cxd2099/Makefile delete mode 100644 drivers/staging/media/cxd2099/TODO -- 2.13.6
[PATCH v2 1/7] [media] ddbridge/ci: further deduplicate code/logic in ddb_ci_attach()
From: Daniel Scheller Deduplicate the checks for a valid ptr in port->en, and also handle the default case to also catch eventually yet unsupported CI hardware. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-ci.c | 12 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 5828111487b0..ed19890710d6 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -325,24 +325,20 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) case DDB_CI_EXTERNAL_SONY: cxd_cfg.bitrate = bitrate; port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); - if (!port->en) - return -ENODEV; break; - case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: ci_xo2_attach(port); - if (!port->en) - return -ENODEV; break; - case DDB_CI_INTERNAL: ci_attach(port); - if (!port->en) - return -ENODEV; break; + default: + return -ENODEV; } + if (!port->en) + return -ENODEV; dvb_ca_en50221_init(port->dvb[0].adap, port->en, 0, 1); return 0; } -- 2.13.6
[PATCH v2 3/7] [media] ddbridge: adapt cxd2099 attach to new i2c_client way
From: Daniel Scheller Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/pci/ddbridge/ddbridge-ci.c | 62 +--- drivers/media/pci/ddbridge/ddbridge.h| 1 + 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index ed19890710d6..6585ef54ac22 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -172,6 +172,7 @@ static void ci_attach(struct ddb_port *port) memcpy(&ci->en, &en_templ, sizeof(en_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; } @@ -304,6 +305,7 @@ static void ci_xo2_attach(struct ddb_port *port) memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; ci->port->creg = 0; @@ -311,20 +313,58 @@ static void ci_xo2_attach(struct ddb_port *port) write_creg(ci, 0x08, 0x08); } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 72000, - .adr = 0x40, .polarity = 1, .clock_mode = 1, .max_i2c = 512, }; +static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) +{ + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.bitrate = bitrate; + cxd_cfg.en = &port->en; + + request_module(board_info.type); + + client = i2c_new_device(&port->i2c->adap, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!port->en) + goto err_i2c; + + port->dvb[0].i2c_client[0] = client; + port->en_freedata = 0; + return 0; + +err_i2c: + i2c_unregister_device(client); +err_ret: + dev_err(port->dev->dev, "CXD2099AR attach failed\n"); + return -ENODEV; +} + int ddb_ci_attach(struct ddb_port *port, u32 bitrate) { + int ret; + switch (port->type) { case DDB_CI_EXTERNAL_SONY: - cxd_cfg.bitrate = bitrate; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + ret = ci_cxd2099_attach(port, bitrate); + if (ret) + return -ENODEV; break; case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: @@ -345,11 +385,23 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { + struct i2c_client *client; + if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - kfree(port->en->data); + + client = port->dvb[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* free alloc'ed memory if needed */ + if (port->en_freedata) + kfree(port->en->data); + port->en = NULL; } } diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 095457737bc1..f223dc6c9963 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -276,6 +276,7 @@ struct ddb_port { struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + u8 en_freedata; struct ddb_dvb dvb[2]; u32gap; u32obr; -- 2.13.6
[PATCH v2 2/7] [media] staging/cxd2099: convert to regmap API
From: Daniel Scheller Convert the cxd2099 driver to use regmap for I2C accesses, removing all own i2c_*() functions. With that, make the driver a proper I2C client driver. This also adds the benefit of having a proper cleanup function (cxd2099_remove() in this case) that takes care of resource cleanup upon I2C client deregistration. At this point, keep the static inline declared cxd2099_attach() function so that drivers using the legacy/proprietary style attach way still compile, albeit lacking the cxd2099 driver functionality. This is taken care of in the next two patches. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/staging/media/cxd2099/cxd2099.c | 209 drivers/staging/media/cxd2099/cxd2099.h | 11 +- 2 files changed, 108 insertions(+), 112 deletions(-) diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/staging/media/cxd2099/cxd2099.c index dc9cbd8f2104..c0a5849b76bb 100644 --- a/drivers/staging/media/cxd2099/cxd2099.c +++ b/drivers/staging/media/cxd2099/cxd2099.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,8 +34,9 @@ static int read_data(struct dvb_ca_en50221 *ca, int slot, u8 *ebuf, int ecount); struct cxd { struct dvb_ca_en50221 en; - struct i2c_adapter *i2c; struct cxd2099_cfg cfg; + struct i2c_client *client; + struct regmap *regmap; u8 regs[0x23]; u8 lastaddress; @@ -56,69 +58,12 @@ struct cxd { u8 wbuf[1028]; }; -static int i2c_write_reg(struct i2c_adapter *adapter, u8 adr, -u8 reg, u8 data) -{ - u8 m[2] = {reg, data}; - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = m, .len = 2}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - dev_err(&adapter->dev, - "Failed to write to I2C register %02x@%02x!\n", - reg, adr); - return -1; - } - return 0; -} - -static int i2c_write(struct i2c_adapter *adapter, u8 adr, -u8 *data, u16 len) -{ - struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; - - if (i2c_transfer(adapter, &msg, 1) != 1) { - dev_err(&adapter->dev, "Failed to write to I2C!\n"); - return -1; - } - return 0; -} - -static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *val) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - dev_err(&adapter->dev, "error in %s()\n", __func__); - return -1; - } - return 0; -} - -static int i2c_read(struct i2c_adapter *adapter, u8 adr, - u8 reg, u8 *data, u16 n) -{ - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = data, .len = n} }; - - if (i2c_transfer(adapter, msgs, 2) != 2) { - dev_err(&adapter->dev, "error in %s()\n", __func__); - return -1; - } - return 0; -} - static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) { int status = 0; if (ci->lastaddress != adr) - status = i2c_write_reg(ci->i2c, ci->cfg.adr, 0, adr); + status = regmap_write(ci->regmap, 0, adr); if (!status) { ci->lastaddress = adr; @@ -127,7 +72,7 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u16 n) if (ci->cfg.max_i2c && len > ci->cfg.max_i2c) len = ci->cfg.max_i2c; - status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, len); + status = regmap_raw_read(ci->regmap, 1, data, len); if (status) return status; data += len; @@ -145,64 +90,66 @@ static int read_reg(struct cxd *ci, u8 reg, u8 *val) static int read_pccard(struct cxd *ci, u16 address, u8 *data, u8 n) { int status; - u8 addr[3] = {2, address & 0xff, address >> 8}; + u8 addr[2] = {address & 0xff, address >> 8}; - status = i2c_write(ci->i2c, ci->cfg.adr, addr, 3); + status = regmap_raw_write(ci->regmap, 2, addr, 2); if (!status) - status = i2c_read(ci->i2c, ci->cfg.adr, 3, data, n); + status = regmap_raw_read(ci->regmap, 3, data, n); return s
[PATCH v2 6/7] [media] cxd2099: move driver out of staging into dvb-frontends
From: Daniel Scheller According to the TODO file, this driver only landed in staging because of the way device nodes and data transfers are handled. Besides that this way (use of secX devices) has become sort of standard to date (ie. VDR supports this literally since ages via the ddci plugin, TVHeadend received this functionality lately, and minisatip being currently worked on regarding this), most importantly this I2C client only driver isn't even responsible for setting up device nodes, not for handling data transfer and so on, but only serves as interface for the dvb_ca_en50221 subsystem, just like every other DVB card out in the wild, with hard-wired or such flexible CA interfaces. And, it would even work with cards having the cxd2099 controller hard-wired. Also, this driver received quite some love and even is a proper I2C client driver by now. So, as this driver acts as a EN50221 frontend device, move it to dvb-frontends. There is no need to keep it buried in staging. This commit also updates all affected Kconfig and Makefile's, and adds MEDIA_AUTOSELECT depends to ddbridge and ngene. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/dvb-frontends/Kconfig | 12 drivers/media/dvb-frontends/Makefile | 1 + .../{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.c | 0 .../{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.h | 0 drivers/media/pci/ddbridge/Kconfig | 1 + drivers/media/pci/ddbridge/Makefile | 3 --- drivers/media/pci/ngene/Kconfig | 1 + drivers/media/pci/ngene/Makefile | 3 --- drivers/staging/media/Kconfig| 2 -- drivers/staging/media/Makefile | 1 - drivers/staging/media/cxd2099/Kconfig| 12 drivers/staging/media/cxd2099/Makefile | 4 drivers/staging/media/cxd2099/TODO | 12 13 files changed, 15 insertions(+), 37 deletions(-) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.c (100%) rename drivers/{staging/media/cxd2099 => media/dvb-frontends}/cxd2099.h (100%) delete mode 100644 drivers/staging/media/cxd2099/Kconfig delete mode 100644 drivers/staging/media/cxd2099/Makefile delete mode 100644 drivers/staging/media/cxd2099/TODO diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index d17722eb4456..ca8c7ed079dd 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -904,6 +904,18 @@ config DVB_HELENE help Say Y when you want to support this frontend. +comment "Common Interface (EN50221) controller drivers" + depends on DVB_CORE + +config DVB_CXD2099 + tristate "CXD2099AR Common Interface driver" + depends on DVB_CORE && I2C + ---help--- + A driver for the CI controller currently found mostly on + Digital Devices DuoFlex CI (single) addon modules. + + Say Y when you want to support these devices. + comment "Tools to develop new frontends" config DVB_DUMMY_FE diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index 4be59fed4536..abbd76ede540 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -129,3 +129,4 @@ obj-$(CONFIG_DVB_HORUS3A) += horus3a.o obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o obj-$(CONFIG_DVB_HELENE) += helene.o obj-$(CONFIG_DVB_ZD1301_DEMOD) += zd1301_demod.o +obj-$(CONFIG_DVB_CXD2099) += cxd2099.o diff --git a/drivers/staging/media/cxd2099/cxd2099.c b/drivers/media/dvb-frontends/cxd2099.c similarity index 100% rename from drivers/staging/media/cxd2099/cxd2099.c rename to drivers/media/dvb-frontends/cxd2099.c diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h similarity index 100% rename from drivers/staging/media/cxd2099/cxd2099.h rename to drivers/media/dvb-frontends/cxd2099.h diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index f43d0b83fc0c..a422dde2f34a 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -13,6 +13,7 @@ config DVB_DDBRIDGE select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index f58fdec50eab..745b37d07558 100644 --- a/drivers/media/pci/ddbridge/Makefile +++
[PATCH v2 4/7] [media] ngene: adapt cxd2099 attach to the new i2c_client way
From: Daniel Scheller Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Also, add I2C_FUNC_I2C to the I2C interface functionality. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/pci/ngene/ngene-core.c | 41 drivers/media/pci/ngene/ngene-i2c.c | 2 +- drivers/media/pci/ngene/ngene.h | 1 + 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 8c92cb7f7e72..80db777cb7ec 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1562,9 +1562,8 @@ static int init_channels(struct ngene *dev) return 0; } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 62000, - .adr = 0x40, .polarity = 0, .clock_mode = 0, }; @@ -1572,18 +1571,52 @@ static struct cxd2099_cfg cxd_cfg = { static void cxd_attach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.en = &ci->en; + + request_module(board_info.type); + + client = i2c_new_device(&dev->channel[0].i2c_adapter, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!ci->en) + goto err_i2c; - ci->en = cxd2099_attach(&cxd_cfg, dev, &dev->channel[0].i2c_adapter); ci->dev = dev; + dev->channel[0].i2c_client[0] = client; + return; + +err_i2c: + i2c_unregister_device(client); +err_ret: + printk(KERN_ERR DEVICE_NAME ": CXD2099AR attach failed\n"); return; } static void cxd_detach(struct ngene *dev) { struct ngene_ci *ci = &dev->ci; + struct i2c_client *client; dvb_ca_en50221_release(ci->en); - kfree(ci->en); + + client = dev->channel[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + ci->en = NULL; } diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index 3004947f300b..092d46c2a3a9 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -147,7 +147,7 @@ static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, static u32 ngene_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm ngene_i2c_algo = { diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 02dbd18f92d0..caf8602c7459 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -630,6 +630,7 @@ struct ngene_vopen { struct ngene_channel { struct device device; struct i2c_adapteri2c_adapter; + struct i2c_client*i2c_client[1]; struct ngene *dev; int number; -- 2.13.6
[PATCH v2 7/7] [media] MAINTAINERS: add entry for cxd2099
From: Jasmin Jessich The cxd2099 driver is now maintained and being taken care of by * Jasmin Jessich Signed-off-by: Jasmin Jessich --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index aee793bff977..c3b689e2583e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8540,6 +8540,14 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: drivers/media/dvb-frontends/ascot2e* +MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS +M: Jasmin Jessich +L: linux-media@vger.kernel.org +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/cxd2099* + MEDIA DRIVERS FOR CXD2841ER M: Sergey Kozlov M: Abylay Ospan -- 2.13.6
[PATCH v2 5/7] [media] staging/cxd2099: remove remainders from old attach way
From: Daniel Scheller As all drivers using the cxd2099 are converted to handle attach/detach the generic I2C client way, the static inline cxd2099_attach isn't required anymore. Thus cleanup cxd2099.h from the remainders, the adr struct member isn't used anymore aswell. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/staging/media/cxd2099/cxd2099.h | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/staging/media/cxd2099/cxd2099.h b/drivers/staging/media/cxd2099/cxd2099.h index 679e87512799..8fa45a4c615a 100644 --- a/drivers/staging/media/cxd2099/cxd2099.h +++ b/drivers/staging/media/cxd2099/cxd2099.h @@ -20,7 +20,6 @@ struct cxd2099_cfg { u32 bitrate; - u8 adr; u8 polarity; u8 clock_mode; @@ -30,13 +29,4 @@ struct cxd2099_cfg { struct dvb_ca_en50221 **en; }; -/* TODO: remove when done */ -static inline struct -dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv, - struct i2c_adapter *i2c) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - #endif -- 2.13.6
[PATCH] [media] dvb_ca_en50221: fix severity of successful CAM init log message
From: Daniel Scheller A successful CA module initialisation isn't an error. Change the log print to info severity accordingly. Cc: Jasmin Jessich Signed-off-by: Daniel Scheller --- drivers/media/dvb-core/dvb_ca_en50221.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 204d0f6c678d..97365a863519 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -1254,8 +1254,8 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, ca->pub->slot_ts_enable(ca->pub, slot); sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; dvb_ca_en50221_thread_update_delay(ca); - pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", - ca->dvbdev->adapter->num); + pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", + ca->dvbdev->adapter->num); break; case DVB_CA_SLOTSTATE_RUNNING: -- 2.16.1
[PATCH 01/12] [media] ngene: add two additional PCI IDs
From: Daniel Scheller Add two more device IDs for cards supported by the ngene driver. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index bb49620540c5..49f78bb31537 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -749,6 +749,8 @@ static const struct ngene_info ngene_info_terratec = { // static const struct pci_device_id ngene_id_tbl[] = { + NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5), NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), -- 2.16.1
[PATCH 08/12] [media] ngene: deduplicate I2C adapter evaluation
From: Daniel Scheller The I2C adapter evaluation (based on chan->number) is duplicated at several places (tuner_attach_() functions, demod_attach_stv0900() and cineS2_probe()). Clean this up by wrapping that construct in a separate function which all users of that can pass the ngene_channel pointer and get the correct I2C adapter from. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 41 +-- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 00b100660784..dff55c7c9f86 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -118,17 +118,25 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) /* Demod/tuner attachment ***/ // +static struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan) +{ + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + return &chan->dev->channel[0].i2c_adapter; + + return &chan->dev->channel[1].i2c_adapter; +} + static int tuner_attach_stv6110(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; struct stv6110x_config *tunerconf = (struct stv6110x_config *) chan->dev->card_info->tuner_config[chan->number]; const struct stv6110x_devctl *ctl; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ if (chan->number < 2) i2c = &chan->dev->channel[0].i2c_adapter; else @@ -158,16 +166,10 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) static int tuner_attach_stv6111(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); if (!fe) { fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); @@ -197,10 +199,9 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; - i2c = &chan->dev->channel[0].i2c_adapter; if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); @@ -240,7 +241,7 @@ static int tuner_tda18212_ping(struct ngene_channel *chan, static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct i2c_client *client; struct tda18212_config config = { .fe = chan->fe, @@ -262,12 +263,6 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) else board_info.addr = 0x60; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - /* * due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when @@ -320,7 +315,7 @@ static int tuner_attach_probe(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -620,7 +615,7 @@ static int port_has_xo
[PATCH 03/12] [media] ngene: use defines to identify the demod_type
From: Daniel Scheller Make it more clear which demod_type is used for which hardware by having defines for the possible demod_type values. With that, change the demod_type evaluation in tuner_attach_probe() to a switch-case instead of an if() for each possible value. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 11 +++ drivers/media/pci/ngene/ngene.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 1de8cbee..065b83ee569b 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -123,10 +123,13 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) static int tuner_attach_probe(struct ngene_channel *chan) { - if (chan->demod_type == 0) + switch (chan->demod_type) { + case DEMOD_TYPE_STV090X: return tuner_attach_stv6110(chan); - if (chan->demod_type == 1) + case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); + } + return -EINVAL; } @@ -251,7 +254,7 @@ static int cineS2_probe(struct ngene_channel *chan) i2c = &chan->dev->channel[1].i2c_adapter; if (port_has_stv0900(i2c, chan->number)) { - chan->demod_type = 0; + chan->demod_type = DEMOD_TYPE_STV090X; fe_conf = chan->dev->card_info->fe_config[chan->number]; /* demod found, attach it */ rc = demod_attach_stv0900(chan); @@ -280,7 +283,7 @@ static int cineS2_probe(struct ngene_channel *chan) return -EIO; } } else if (port_has_drxk(i2c, chan->number^2)) { - chan->demod_type = 1; + chan->demod_type = DEMOD_TYPE_DRXK; demod_attach_drxk(chan, i2c); } else { dev_err(pdev, "No demod found on chan %d\n", chan->number); diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index caf8602c7459..9724701a3274 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -51,6 +51,9 @@ #define VIDEO_CAP_MPEG4 512 #endif +#define DEMOD_TYPE_STV090X 0 +#define DEMOD_TYPE_DRXK1 + enum STREAM { STREAM_VIDEOIN1 = 0,/* ITU656 or TS Input */ STREAM_VIDEOIN2, -- 2.16.1
[PATCH 00/12] ngene-updates: Hardware support, TS buffer shift fix
From: Daniel Scheller Some love for the ngene driver, which runs the older Micronas nGene based cards from Digital Devices like the cineS2 v5.5. This series changes: - Two more PCI IDs for more supported PCIe bridge hardware - Conversion of all printk() to more proper dev_*() based logging (the module_init rather uses pr_*() logging since there's no *dev available yet). - Support for all available DuoFlex addon modules from that vendor. All addon modules are electrically compatible and use the same interface, and the addons work very well on the aging ngene hardware. - Check for CXD2099AR addon modules before blindly trying to attach them, removing unnecessary and maybe irritating error logging if such module isn't present. - Workaround a hardware quirk in conjunction with the CXD2099AR module, CA modules and CAM control communication, causing the TS input buffer to shift albeit different communication paths are ought to be in use. This series is based on the CXD2099 regmap conversion series, see [1]. Especially [2] is required for the STV0367 enablement patch (and the following ones) since the use of the TDA18212 I2C tuner client relies on the i2c_client variable to be present, which is added in the forementioned CXD2099 series. Please pick this up and merge. [1] https://www.spinics.net/lists/linux-media/msg129183.html [2] https://www.spinics.net/lists/linux-media/msg129187.html Daniel Scheller (12): [media] ngene: add two additional PCI IDs [media] ngene: convert kernellog printing from printk() to dev_*() macros [media] ngene: use defines to identify the demod_type [media] ngene: support STV0367 DVB-C/T DuoFlex addons [media] ngene: add XO2 module support [media] ngene: add support for Sony CXD28xx-based DuoFlex modules [media] ngene: add support for DuoFlex S2 V4 addon modules [media] ngene: deduplicate I2C adapter evaluation [media] ngene: check for CXD2099AR presence before attaching [media] ngene: don't treat non-existing demods as error [media] ngene: move the tsin_exchange() stripcopy block into a function [media] ngene: compensate for TS buffer offset shifts drivers/media/pci/ngene/Kconfig | 6 + drivers/media/pci/ngene/ngene-cards.c | 590 ++ drivers/media/pci/ngene/ngene-core.c | 101 +++--- drivers/media/pci/ngene/ngene-dvb.c | 122 +-- drivers/media/pci/ngene/ngene.h | 23 ++ 5 files changed, 721 insertions(+), 121 deletions(-) -- 2.16.1
[PATCH 04/12] [media] ngene: support STV0367 DVB-C/T DuoFlex addons
From: Daniel Scheller Add support for STV0367+TDA18212 based DuoFlex CT addon modules. For this, add a demod probe function and all necessary demod/tuner attach functions which use existing auxiliary drivers (stv0367 and tda18212) to support this hardware. As tda18212 is an I2C client driver, proper cleanup code is added to the deregistration sequence in ngene-core. To not cause use- after-free situations when there's a CXD2099 I2C client connected, which is rather freed in ngene-core.c:cxd_detach(), add i2c_client_fe to struct ngene_channel to keep track if the i2c_client was allocated by a frontend driver, rather than the CI code paths. Also move the I2C access functions to the top of the file and add the required read_regs() function for the tda18212 ping to work. This adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the STV0367 demod driver and TDA18212 tuner driver to Kconfig aswell. Signed-off-by: Daniel Scheller --- This and the following patches require the i2c_client variable that is added by https://www.spinics.net/lists/linux-media/msg129187.html so that makes it a somewhat hard-dependency. drivers/media/pci/ngene/Kconfig | 2 + drivers/media/pci/ngene/ngene-cards.c | 194 ++ drivers/media/pci/ngene/ngene-core.c | 12 +++ drivers/media/pci/ngene/ngene.h | 2 + 4 files changed, 191 insertions(+), 19 deletions(-) diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index 390ed75fe438..c3254f9dc8ad 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -8,6 +8,8 @@ config DVB_NGENE select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 065b83ee569b..7ec5f68b1ec7 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -42,8 +42,42 @@ #include "drxk.h" #include "drxd.h" #include "dvb-pll.h" +#include "stv0367.h" +#include "stv0367_priv.h" +#include "tda18212.h" +// +/* I2C transfer functions used for demod/tuner probing***/ +// + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg >> 8, reg & 0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} +static int i2c_read_regs(struct i2c_adapter *adapter, +u8 adr, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len} }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} // /* Demod/tuner attachment ***/ // @@ -85,7 +119,6 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } - static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ngene_channel *chan = fe->sec_priv; @@ -121,6 +154,89 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) return 0; } +static int tuner_tda18212_ping(struct ngene_channel *chan, + struct i2c_adapter *i2c, + unsigned short adr) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 tda_id[2]; + u8 subaddr = 0x00; + + dev_dbg(pdev, "stv0367-tda18212 tuner ping\n"); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + + if
[PATCH 12/12] [media] ngene: compensate for TS buffer offset shifts
From: Daniel Scheller A possible hardware bug was discovered when using CA addon hardware attached to the ngene hardware, in that the TS input buffer much likely will shift and thus become unaligned to 188 byte blocks (a full TS frame) when things like CA module initialisation (which happens via differing communication paths) takes place. This causes the TS NULL removal in tsin_exchange() to fail to detect this previously inserted data and thus causes userspace applications to receive data they didn't sent beforehand and ultimately can cause troubles. On driver load with an inserted CAM, buffers are fine at first (note that the driver has to keep the communication running from/to the card by inserting TS NULL frames, this is done in tsout_exchange() via FillTSBuffer() - that data is simply sent back by the hardware): offset | 01 2 3 4 5 188 189 190 191 192 193 376 data | 47 1f ff 10 6f 6f 47 1f ff 10 6f 6f 47 After a few seconds, the CA module is recognised and initialised, which is signalled by dvb_ca_en50221: dvb_ca adapter X: DVB CAM detected and initialised successfully This is where the first shift happens (this is always four bytes), buffer becomes like this: offset | 01 2 3 4 5 188 189 190 191 192 193 376 data | 6f 6f 6f 6f 47 1f 6f 6f 6f 6f 47 1f 6f Next, VDR, TVHeadend or any other CI aware application is started, buffers will shift by even more bytes. It is believed this is due to the hardware not handling control and data bytes properly distinct, and control data having an influence on the actual data stream, which we cannot properly detect at the driver level. Workaround this hardware quirk by adding a detection for the TS sync byte 0x47 before each TS frame copy, scan for a new SYNC byte and a TS NULL packet if buffers become unaligned, take note of that offset and apply that when copying data to the DVB ring buffers. The last <188 bytes from the hardware buffers are stored in a temp buffer (tsin_buffer), for which the remainder will be in the beginning of the next hardware buffer (next iteration if tsin_exchange()). That remainder will be appended to the temp buffer and finally sent to the DVB ring buffer. The resulting TS stream is perfectly fine, and the TS NULL packets inserted by the driver which are sent back are properly removed. The resulting offset is being clamped to 188 byte segments (one TS packet). Though this can result in a repeated TS packet if the overall offset grows beyond this (and it will grow only on CA initialisation), this is still way better than unaligned TS frames and data sent to userspace that just isn't supposed to be there. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-dvb.c | 80 - drivers/media/pci/ngene/ngene.h | 3 ++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 6d72b9f69418..5abf69f6bc4b 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -38,6 +38,9 @@ #include "ngene.h" +static int ci_tsfix = 1; +module_param(ci_tsfix, int, 0444); +MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)"); // /* COMMAND API interface / @@ -123,6 +126,24 @@ static u32 overflow; static u32 stripped; #endif +static int tsin_find_offset(void *buf, u32 len) +{ + int i, l; + + l = len - sizeof(fill_ts); + if (l <= 0) + return -1; + + for (i = 0; i < l; i++) { + if (((char *)buf)[i] == 0x47) { + if (!memcmp(buf + i, fill_ts, sizeof(fill_ts))) + return i; + } + } + + return -1; +} + static inline void tsin_copy_stripped(struct ngene *dev, void *buf) { if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { @@ -153,18 +174,75 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; struct ngene *dev = chan->dev; - + int tsoff; if (flags & DF_SWAP32) swap_buffer(buf, len); if (dev->ci.en && chan->number == 2) { + /* blindly copy buffers if ci_tsfix is disabled */ + if (!ci_tsfix) { + while (len >= 188) { + tsin_copy_stripped(dev, buf); + + buf += 188; + len -= 188; + } + return NULL; + } + + /* ci_tsfix = 1 */ + + /* +
[PATCH 05/12] [media] ngene: add XO2 module support
From: Daniel Scheller Detect and initialise modules equipped with XO2 interfaces (Lattice MachXO2). This requires a few more I2C transfer functions which this adds aswell. Defines for the different possible (available) module types are added to ngene.h. The support for the actual tuners contained on these addon modules is kept separate from this commit and is being added with the next commits. The xo2names array is temporarily marked __maybe_unused to silence a corresponding compiler warning at this stage. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 144 +- drivers/media/pci/ngene/ngene.h | 12 +++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 7ec5f68b1ec7..05b8e56999ec 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -50,6 +50,32 @@ /* I2C transfer functions used for demod/tuner probing***/ // +static int i2c_io(struct i2c_adapter *adapter, u8 adr, + u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = wbuf, .len = wlen }, + {.addr = adr, .flags = I2C_M_RD, + .buf = rbuf, .len = rlen } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, +u8 reg, u8 val) +{ + u8 msg[2] = {reg, val}; + + return i2c_write(adap, adr, msg, 2); +} + static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) { struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, @@ -78,6 +104,12 @@ static int i2c_read_regs(struct i2c_adapter *adapter, return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; } + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) +{ + return i2c_read_regs(adapter, adr, reg, val, 1); +} + // /* Demod/tuner attachment ***/ // @@ -390,12 +422,98 @@ static int demod_attach_drxk(struct ngene_channel *chan, return 0; } +// +/* XO2 related lists and functions **/ +// + +static char __maybe_unused *xo2names[] = { + "DUAL DVB-S2", + "DUAL DVB-C/T/T2", + "DUAL DVB-ISDBT", + "DUAL DVB-C/C2/T/T2", + "DUAL ATSC", + "DUAL DVB-C/C2/T/T2/I", +}; + +static int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 addr = 0x10; + u8 val, data[2]; + int res; + + res = i2c_read_regs(i2c, addr, 0x04, data, 2); + if (res < 0) + return res; + + if (data[0] != 0x01) { + dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number); + return -1; + } + + i2c_read_reg(i2c, addr, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, addr, 0x08, 0x00); + msleep(100); + } + /* Enable tuner power, disable pll, reset demods */ + i2c_write_reg(i2c, addr, 0x08, 0x04); + usleep_range(2000, 3000); + /* Release demod resets */ + i2c_write_reg(i2c, addr, 0x08, 0x07); + + /* +* speed: 0=55,1=75,2=90,3=104 MBit/s +* Note: The ngene hardware must be run at 75 MBit/s compared +* to more modern ddbridge hardware which runs at 90 MBit/s, +* else there will be issues with the data transport and non- +* working secondary/slave demods/tuners. +*/ + i2c_write_reg(i2c, addr, 0x09, 1); + + i2c_write_reg(i2c, addr, 0x0a, 0x01); + i2c_write_reg(i2c, addr, 0x0b, 0x01); + + usleep_range(2000, 3000); + /* Start XO2 PLL */ + i2c_write_reg(i2c, addr, 0x08, 0x87); + + return 0; +} + +static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id) +{ + u8 probe[1] = { 0x00 }, data[4]; + u8 addr = 0x10; + + *type = NGENE_XO2_TYPE_NONE; + + if (i2c_io(i2c
[PATCH 10/12] [media] ngene: don't treat non-existing demods as error
From: Daniel Scheller When probing the I2C busses in cineS2_probe(), it's no error when there's no hardware connected to the probed expansion connector, so print this informal message with info severity. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index d603d0af703e..37e9f0eb6d20 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -728,7 +728,7 @@ static int cineS2_probe(struct ngene_channel *chan) dev_info(pdev, "STV0367 on channel %d\n", chan->number); demod_attach_stv0367(chan, i2c); } else { - dev_err(pdev, "No demod found on chan %d\n", chan->number); + dev_info(pdev, "No demod found on chan %d\n", chan->number); return -ENODEV; } return 0; -- 2.16.1
[PATCH 02/12] [media] ngene: convert kernellog printing from printk() to dev_*() macros
From: Daniel Scheller Convert all printk() and pr_*() kernel log printing to rather use the dev_*() macros. Not only is it discouraged to use printk() (checkpatch even complains about that), but also this helps identifying the exact PCI device for any printed event, and it makes almost all printing shorter in terms of code style since there's no need to use KERN_* DEVICE_NAME any more (dev_*() will take care of this). Since the dprintk macro define isn't used anymore, remove it. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 75 --- drivers/media/pci/ngene/ngene-core.c | 75 +-- drivers/media/pci/ngene/ngene-dvb.c | 4 +- 3 files changed, 84 insertions(+), 70 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 49f78bb31537..1de8cbee 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -23,6 +23,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -48,6 +50,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -63,7 +66,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); if (ctl == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + dev_err(pdev, "No STV6110X found!\n"); return -ENODEV; } @@ -100,6 +103,7 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct dvb_frontend *fe; @@ -110,7 +114,7 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); + dev_err(pdev, "No TDA18271 found!\n"); return -ENODEV; } @@ -128,6 +132,7 @@ static int tuner_attach_probe(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -144,7 +149,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 : STV090x_DEMODULATOR_1); if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + dev_err(pdev, "No STV0900 found!\n"); return -ENODEV; } @@ -154,7 +159,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, 0, chan->dev->card_info->lnb[chan->number])) { - printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dev_err(pdev, "No LNBH24 found!\n"); dvb_frontend_detach(chan->fe); chan->fe = NULL; return -ENODEV; @@ -211,6 +216,7 @@ static int port_has_drxk(struct i2c_adapter *i2c, int port) static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxk_config config; memset(&config, 0, sizeof(config)); @@ -220,7 +226,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, chan->fe = dvb_attach(drxk_attach, &config, i2c); if (!chan->fe) { - printk(KERN_ERR "No DRXK found!\n"); + dev_err(pdev, "No DRXK found!\n"); return -ENODEV; } chan->fe->sec_priv = chan; @@ -231,6 +237,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, static int cineS2_probe(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; @@ -269,14 +276,14 @@ static int cineS2_probe(struct ngene_channel *chan)
[PATCH 09/12] [media] ngene: check for CXD2099AR presence before attaching
From: Daniel Scheller Currently, if there's no CXD2099AR attached to any expansion connector of the ngene hardware, it will complain with this on every module load: cxd2099 1-0040: No CXD2099AR detected at 0x40 cxd2099: probe of 1-0040 failed with error -5 ngene :02:00.0: CXD2099AR attach failed This happens due to the logic assuming such hardware is always there and blindly tries to attach the cxd2099 I2C driver. Rather add a probe function (in ngene-cards.c with a prototype in ngene.h) to check for the existence of such hardware before probing, and don't try further if no CXD2099 was found. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 19 +++ drivers/media/pci/ngene/ngene-core.c | 14 ++ drivers/media/pci/ngene/ngene.h | 3 +++ 3 files changed, 36 insertions(+) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index dff55c7c9f86..d603d0af703e 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -505,6 +505,25 @@ static int port_has_stv0367(struct i2c_adapter *i2c) return 1; } +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type) +{ + u8 val; + u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; + struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, + .buf = probe, .len = 4 }, + { .addr = 0x40, .flags = I2C_M_RD, + .buf = data, .len = 4 } }; + val = i2c_transfer(i2c, msgs, 2); + if (val != 2) + return 0; + + if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) + *type = 2; + else + *type = 1; + return 1; +} + static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 526d0adfa427..f69a8fc1ec2a 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1589,6 +1589,20 @@ static void cxd_attach(struct ngene *dev) .addr = 0x40, .platform_data = &cxd_cfg, }; + int ret; + u8 type; + + /* check for CXD2099AR presence before attaching */ + ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type); + if (!ret) { + dev_dbg(pdev, "No CXD2099AR found\n"); + return; + } + + if (type != 1) { + dev_warn(pdev, "CXD2099AR is uninitialized!\n"); + return; + } cxd_cfg.en = &ci->en; diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 72195f6552b3..66d8eaa28549 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -909,6 +909,9 @@ int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); void set_transfer(struct ngene_channel *chan, int state); void FillTSBuffer(void *Buffer, int Length, u32 Flags); +/* Provided by ngene-cards.c */ +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type); + /* Provided by ngene-i2c.c */ int ngene_i2c_init(struct ngene *dev, int dev_nr); -- 2.16.1
[PATCH 07/12] [media] ngene: add support for DuoFlex S2 V4 addon modules
From: Daniel Scheller Add support for the STV0910/STV6111/LNBH25 based DuoFlex S2 V4 DVB-S2 addon modules by recognizing them from their XO2 type value and using the auxiliary stv0910, stv6111 and lnbh25 driver to form a complete DVB frontend. This also adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the STV0910, STV6111 and LNBH25 demod/tuner/LNB-IC drivers to Kconfig. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/Kconfig | 3 ++ drivers/media/pci/ngene/ngene-cards.c | 83 +++ 2 files changed, 86 insertions(+) diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index f717567f54a5..e06d019996f3 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -11,6 +11,9 @@ config DVB_NGENE select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index cdc8db14c606..00b100660784 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -46,6 +46,9 @@ #include "stv0367_priv.h" #include "tda18212.h" #include "cxd2841er.h" +#include "stv0910.h" +#include "stv6111.h" +#include "lnbh25.h" // /* I2C transfer functions used for demod/tuner probing***/ @@ -152,6 +155,30 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } +static int tuner_attach_stv6111(struct ngene_channel *chan) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); + if (!fe) { + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); + if (!fe) { + dev_err(pdev, "stv6111_attach() failed!\n"); + return -ENODEV; + } + } + return 0; +} + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ngene_channel *chan = fe->sec_priv; @@ -283,6 +310,8 @@ static int tuner_attach_probe(struct ngene_channel *chan) case DEMOD_TYPE_SONY_C2T2: case DEMOD_TYPE_SONY_C2T2I: return tuner_attach_tda18212(chan, chan->demod_type); + case DEMOD_TYPE_STV0910: + return tuner_attach_stv6111(chan); } return -EINVAL; @@ -326,6 +355,54 @@ static int demod_attach_stv0900(struct ngene_channel *chan) return 0; } +static struct stv0910_cfg stv0910_p = { + .adr = 0x68, + .parallel = 1, + .rptlvl = 4, + .clk = 3000, +}; + +static struct lnbh25_config lnbh25_cfg = { + .i2c_address = 0x0c << 1, + .data2_config = LNBH25_TEN +}; + +static int demod_attach_stv0910(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct stv0910_cfg cfg = stv0910_p; + struct lnbh25_config lnbcfg = lnbh25_cfg; + + chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1)); + if (!chan->fe) { + cfg.adr = 0x6c; + chan->fe = dvb_attach(stv0910_attach, i2c, + &cfg, (chan->number & 1)); + } + if (!chan->fe) { + dev_err(pdev, "stv0910_attach() failed!\n"); + return -ENODEV; + } + + /* +* attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit +* i2c addresses +*/ + lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + dev_err(pdev, "lnbh25_attach() failed!\n&
[PATCH 06/12] [media] ngene: add support for Sony CXD28xx-based DuoFlex modules
From: Daniel Scheller Recognize (probe) and support (attach) all Sony CXD28xx based DuoFlex addon modules/cards, namely the DuoFlex CT2 (CXD2837), ISDB-T (CXD2838), C2T2 (CXD2843) and C2T2I (CXD2854). Since all these modules are equipped with a MachXO2 interface, that support is required for the hardware to work. This functionality utilises the auxiliary cxd2841er and tda18212 drivers. This also adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the CXD2841ER demod driver to Kconfig. The __maybe_unused annotation can now be removed from the xo2names array. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/Kconfig | 1 + drivers/media/pci/ngene/ngene-cards.c | 63 --- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index c3254f9dc8ad..f717567f54a5 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -9,6 +9,7 @@ config DVB_NGENE select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 05b8e56999ec..cdc8db14c606 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -45,6 +45,7 @@ #include "stv0367.h" #include "stv0367_priv.h" #include "tda18212.h" +#include "cxd2841er.h" // /* I2C transfer functions used for demod/tuner probing***/ @@ -277,6 +278,10 @@ static int tuner_attach_probe(struct ngene_channel *chan) case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); case DEMOD_TYPE_STV0367: + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: + case DEMOD_TYPE_SONY_C2T2: + case DEMOD_TYPE_SONY_C2T2I: return tuner_attach_tda18212(chan, chan->demod_type); } @@ -358,6 +363,34 @@ static int demod_attach_stv0367(struct ngene_channel *chan, return 0; } +static int demod_attach_cxd28xx(struct ngene_channel *chan, + struct i2c_adapter *i2c, int osc24) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct cxd2841er_config cfg; + + /* the cxd2841er driver expects 8bit/shifted I2C addresses */ + cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1; + + cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500; + cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE | + CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG | + CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL; + + /* attach frontend */ + chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); + + if (!chan->fe) { + dev_err(pdev, "CXD28XX attach failed!\n"); + return -ENODEV; + } + + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) { struct ngene_channel *chan = fe->analog_demod_priv; @@ -426,7 +459,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, /* XO2 related lists and functions **/ // -static char __maybe_unused *xo2names[] = { +static char *xo2names[] = { "DUAL DVB-S2", "DUAL DVB-C/T/T2", "DUAL DVB-ISDBT", @@ -513,7 +546,8 @@ static int cineS2_probe(struct ngene_channel *chan) struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; - u8 xo2_type, xo2_id; + u8 xo2_type, xo2_id, xo2_demodtype; + u8 sony_osc24 = 0; struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; int rc; @@ -537,9 +571,28 @@ static int cineS2_probe(struct ngene_channel *chan) else init_xo2(chan, i2c); - /* TODO: implement support for XO2 module types */ - dev_warn(pdev, "XO2 not supported\n"); - return -ENODEV; + xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id; + + switch (xo2_demodtype) { + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: +
[PATCH 11/12] [media] ngene: move the tsin_exchange() stripcopy block into a function
From: Daniel Scheller Move the copy logic that will skip previously inserted TS NULL frames when moving data to the DVB ring buffers into an own function. This is done to not duplicate code all over the place with the following TS offset shift fixup patch. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-dvb.c | 48 + 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index f71fd41c762c..6d72b9f69418 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -123,6 +123,32 @@ static u32 overflow; static u32 stripped; #endif +static inline void tsin_copy_stripped(struct ngene *dev, void *buf) +{ + if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); +#ifdef DEBUG_CI_XFER + ok++; +#endif + } +#ifdef DEBUG_CI_XFER + else + overflow++; +#endif + } +#ifdef DEBUG_CI_XFER + else + stripped++; + + if (ok % 100 == 0 && overflow) + dev_warn(&dev->pci_dev->dev, +"%s: ok %u overflow %u dropped %u\n", +__func__, ok, overflow, stripped); +#endif +} + void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; @@ -134,28 +160,8 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) if (dev->ci.en && chan->number == 2) { while (len >= 188) { - if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); - wake_up(&dev->tsin_rbuf.queue); -#ifdef DEBUG_CI_XFER - ok++; -#endif - } -#ifdef DEBUG_CI_XFER - else - overflow++; -#endif - } -#ifdef DEBUG_CI_XFER - else - stripped++; + tsin_copy_stripped(dev, buf); - if (ok % 100 == 0 && overflow) - dev_warn(&dev->pci_dev->dev, -"%s: ok %u overflow %u dropped %u\n", -__func__, ok, overflow, stripped); -#endif buf += 188; len -= 188; } -- 2.16.1
[PATCH v2 04/12] [media] ngene: support STV0367 DVB-C/T DuoFlex addons
From: Daniel Scheller Add support for STV0367+TDA18212 based DuoFlex CT addon modules. For this, add a demod probe function and all necessary demod/tuner attach functions which use existing auxiliary drivers (stv0367 and tda18212) to support this hardware. As tda18212 is an I2C client driver, proper cleanup code is added to the deregistration sequence in ngene-core. To not cause use- after-free situations when there's a CXD2099 I2C client connected, which is rather freed in ngene-core.c:cxd_detach(), add i2c_client_fe to struct ngene_channel to keep track if the i2c_client was allocated by a frontend driver, rather than the CI code paths. Also move the I2C access functions to the top of the file and add the required read_regs() function for the tda18212 ping to work. This adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the STV0367 demod driver and TDA18212 tuner driver to Kconfig aswell. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/Kconfig | 2 + drivers/media/pci/ngene/ngene-cards.c | 194 ++ drivers/media/pci/ngene/ngene-core.c | 12 +++ drivers/media/pci/ngene/ngene.h | 2 + 4 files changed, 191 insertions(+), 19 deletions(-) diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index 390ed75fe438..c3254f9dc8ad 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -8,6 +8,8 @@ config DVB_NGENE select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 065b83ee569b..7ec5f68b1ec7 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -42,8 +42,42 @@ #include "drxk.h" #include "drxd.h" #include "dvb-pll.h" +#include "stv0367.h" +#include "stv0367_priv.h" +#include "tda18212.h" +// +/* I2C transfer functions used for demod/tuner probing***/ +// + +static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) +{ + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; +} + +static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) +{ + u8 msg[2] = {reg >> 8, reg & 0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1} }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} +static int i2c_read_regs(struct i2c_adapter *adapter, +u8 adr, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = ®, .len = 1}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = len} }; + + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} // /* Demod/tuner attachment ***/ // @@ -85,7 +119,6 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } - static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ngene_channel *chan = fe->sec_priv; @@ -121,6 +154,89 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) return 0; } +static int tuner_tda18212_ping(struct ngene_channel *chan, + struct i2c_adapter *i2c, + unsigned short adr) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 tda_id[2]; + u8 subaddr = 0x00; + + dev_dbg(pdev, "stv0367-tda18212 tuner ping\n"); + if (chan->fe->ops.i2c_gate_ctrl) + chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); + + if (i2c_read_regs(i2c, adr, subaddr, tda_id, sizeof(tda_id)) < 0) + dev_dbg(pdev, "tda18212 ping 1 fail\n"); + if (i2c_read_regs(i2c, adr, subadd
[PATCH v2 00/12] ngene-updates: Hardware support, TS buffer shift fix
From: Daniel Scheller Sorry for this quick V2 of this series and thus sorry for the traffic, spam and noise. V1 missed a 188-byte clamping in tsin_find_offset() and a recheck for the remaining size of the TS buffer to copy after offset correction. Some love for the ngene driver, which runs the older Micronas nGene based cards from Digital Devices like the cineS2 v5.5. This series changes: - Two more PCI IDs for more supported PCIe bridge hardware - Conversion of all printk() to more proper dev_*() based logging (the module_init rather uses pr_*() logging since there's no *dev available yet). - Support for all available DuoFlex addon modules from that vendor. All addon modules are electrically compatible and use the same interface, and the addons work very well on the aging ngene hardware. - Check for CXD2099AR addon modules before blindly trying to attach them, removing unnecessary and maybe irritating error logging if such module isn't present. - Workaround a hardware quirk in conjunction with the CXD2099AR module, CA modules and CAM control communication, causing the TS input buffer to shift albeit different communication paths are ought to be in use. This series is based on the CXD2099 regmap conversion series, see [1]. Especially [2] is required for the STV0367 enablement patch (and the following ones) since the use of the TDA18212 I2C tuner client relies on the i2c_client variable to be present, which is added in the forementioned CXD2099 series. Please pick this up and merge. [1] https://www.spinics.net/lists/linux-media/msg129183.html [2] https://www.spinics.net/lists/linux-media/msg129187.html Changes since v1: - TS buffer offset correction missed a check for the remaining buffer length before copying the next full 188-byte block, which might could have caused out-of-bound-reads from void *buf. Also, tsin_find_offset returns it's offset clamped to 188 byte boundaries to not accidentally skip over valid TS data. Few typos in the commit message were fixed and a note for the modparam was added, too. Daniel Scheller (12): [media] ngene: add two additional PCI IDs [media] ngene: convert kernellog printing from printk() to dev_*() macros [media] ngene: use defines to identify the demod_type [media] ngene: support STV0367 DVB-C/T DuoFlex addons [media] ngene: add XO2 module support [media] ngene: add support for Sony CXD28xx-based DuoFlex modules [media] ngene: add support for DuoFlex S2 V4 addon modules [media] ngene: deduplicate I2C adapter evaluation [media] ngene: check for CXD2099AR presence before attaching [media] ngene: don't treat non-existing demods as error [media] ngene: move the tsin_exchange() stripcopy block into a function [media] ngene: compensate for TS buffer offset shifts drivers/media/pci/ngene/Kconfig | 6 + drivers/media/pci/ngene/ngene-cards.c | 590 ++ drivers/media/pci/ngene/ngene-core.c | 101 +++--- drivers/media/pci/ngene/ngene-dvb.c | 133 ++-- drivers/media/pci/ngene/ngene.h | 23 ++ 5 files changed, 732 insertions(+), 121 deletions(-) -- 2.16.1
[PATCH v2 01/12] [media] ngene: add two additional PCI IDs
From: Daniel Scheller Add two more device IDs for cards supported by the ngene driver. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index bb49620540c5..49f78bb31537 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -749,6 +749,8 @@ static const struct ngene_info ngene_info_terratec = { // static const struct pci_device_id ngene_id_tbl[] = { + NGENE_ID(0x18c3, 0xab04, ngene_info_cineS2), + NGENE_ID(0x18c3, 0xab05, ngene_info_cineS2v5), NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), -- 2.16.1
[PATCH v2 02/12] [media] ngene: convert kernellog printing from printk() to dev_*() macros
From: Daniel Scheller Convert all printk() and pr_*() kernel log printing to rather use the dev_*() macros. Not only is it discouraged to use printk() (checkpatch even complains about that), but also this helps identifying the exact PCI device for any printed event, and it makes almost all printing shorter in terms of code style since there's no need to use KERN_* DEVICE_NAME any more (dev_*() will take care of this). Since the dprintk macro define isn't used anymore, remove it. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 75 --- drivers/media/pci/ngene/ngene-core.c | 75 +-- drivers/media/pci/ngene/ngene-dvb.c | 4 +- 3 files changed, 84 insertions(+), 70 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 49f78bb31537..1de8cbee 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -23,6 +23,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -48,6 +50,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -63,7 +66,7 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) ctl = dvb_attach(stv6110x_attach, chan->fe, tunerconf, i2c); if (ctl == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV6110X found!\n"); + dev_err(pdev, "No STV6110X found!\n"); return -ENODEV; } @@ -100,6 +103,7 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct dvb_frontend *fe; @@ -110,7 +114,7 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); + dev_err(pdev, "No TDA18271 found!\n"); return -ENODEV; } @@ -128,6 +132,7 @@ static int tuner_attach_probe(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -144,7 +149,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) (chan->number & 1) == 0 ? STV090x_DEMODULATOR_0 : STV090x_DEMODULATOR_1); if (chan->fe == NULL) { - printk(KERN_ERR DEVICE_NAME ": No STV0900 found!\n"); + dev_err(pdev, "No STV0900 found!\n"); return -ENODEV; } @@ -154,7 +159,7 @@ static int demod_attach_stv0900(struct ngene_channel *chan) if (!dvb_attach(lnbh24_attach, chan->fe, i2c, 0, 0, chan->dev->card_info->lnb[chan->number])) { - printk(KERN_ERR DEVICE_NAME ": No LNBH24 found!\n"); + dev_err(pdev, "No LNBH24 found!\n"); dvb_frontend_detach(chan->fe); chan->fe = NULL; return -ENODEV; @@ -211,6 +216,7 @@ static int port_has_drxk(struct i2c_adapter *i2c, int port) static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { + struct device *pdev = &chan->dev->pci_dev->dev; struct drxk_config config; memset(&config, 0, sizeof(config)); @@ -220,7 +226,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, chan->fe = dvb_attach(drxk_attach, &config, i2c); if (!chan->fe) { - printk(KERN_ERR "No DRXK found!\n"); + dev_err(pdev, "No DRXK found!\n"); return -ENODEV; } chan->fe->sec_priv = chan; @@ -231,6 +237,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, static int cineS2_probe(struct ngene_channel *chan) { + struct device *pdev = &chan->dev->pci_dev->dev; struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; @@ -269,14 +276,14 @@ static int cineS2_probe(struct ngene_channel *chan)
[PATCH v2 05/12] [media] ngene: add XO2 module support
From: Daniel Scheller Detect and initialise modules equipped with XO2 interfaces (Lattice MachXO2). This requires a few more I2C transfer functions which this adds aswell. Defines for the different possible (available) module types are added to ngene.h. The support for the actual tuners contained on these addon modules is kept separate from this commit and is being added with the next commits. The xo2names array is temporarily marked __maybe_unused to silence a corresponding compiler warning at this stage. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 144 +- drivers/media/pci/ngene/ngene.h | 12 +++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 7ec5f68b1ec7..05b8e56999ec 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -50,6 +50,32 @@ /* I2C transfer functions used for demod/tuner probing***/ // +static int i2c_io(struct i2c_adapter *adapter, u8 adr, + u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) +{ + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = wbuf, .len = wlen }, + {.addr = adr, .flags = I2C_M_RD, + .buf = rbuf, .len = rlen } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +} + +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +{ + struct i2c_msg msg = {.addr = adr, .flags = 0, + .buf = data, .len = len}; + + return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; +} + +static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, +u8 reg, u8 val) +{ + u8 msg[2] = {reg, val}; + + return i2c_write(adap, adr, msg, 2); +} + static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) { struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, @@ -78,6 +104,12 @@ static int i2c_read_regs(struct i2c_adapter *adapter, return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; } + +static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) +{ + return i2c_read_regs(adapter, adr, reg, val, 1); +} + // /* Demod/tuner attachment ***/ // @@ -390,12 +422,98 @@ static int demod_attach_drxk(struct ngene_channel *chan, return 0; } +// +/* XO2 related lists and functions **/ +// + +static char __maybe_unused *xo2names[] = { + "DUAL DVB-S2", + "DUAL DVB-C/T/T2", + "DUAL DVB-ISDBT", + "DUAL DVB-C/C2/T/T2", + "DUAL ATSC", + "DUAL DVB-C/C2/T/T2/I", +}; + +static int init_xo2(struct ngene_channel *chan, struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + u8 addr = 0x10; + u8 val, data[2]; + int res; + + res = i2c_read_regs(i2c, addr, 0x04, data, 2); + if (res < 0) + return res; + + if (data[0] != 0x01) { + dev_info(pdev, "Invalid XO2 on channel %d\n", chan->number); + return -1; + } + + i2c_read_reg(i2c, addr, 0x08, &val); + if (val != 0) { + i2c_write_reg(i2c, addr, 0x08, 0x00); + msleep(100); + } + /* Enable tuner power, disable pll, reset demods */ + i2c_write_reg(i2c, addr, 0x08, 0x04); + usleep_range(2000, 3000); + /* Release demod resets */ + i2c_write_reg(i2c, addr, 0x08, 0x07); + + /* +* speed: 0=55,1=75,2=90,3=104 MBit/s +* Note: The ngene hardware must be run at 75 MBit/s compared +* to more modern ddbridge hardware which runs at 90 MBit/s, +* else there will be issues with the data transport and non- +* working secondary/slave demods/tuners. +*/ + i2c_write_reg(i2c, addr, 0x09, 1); + + i2c_write_reg(i2c, addr, 0x0a, 0x01); + i2c_write_reg(i2c, addr, 0x0b, 0x01); + + usleep_range(2000, 3000); + /* Start XO2 PLL */ + i2c_write_reg(i2c, addr, 0x08, 0x87); + + return 0; +} + +static int port_has_xo2(struct i2c_adapter *i2c, u8 *type, u8 *id) +{ + u8 probe[1] = { 0x00 }, data[4]; + u8 addr = 0x10; + + *type = NGENE_XO2_TYPE_NONE; + + if (i2c_io(i2c
[PATCH v2 03/12] [media] ngene: use defines to identify the demod_type
From: Daniel Scheller Make it more clear which demod_type is used for which hardware by having defines for the possible demod_type values. With that, change the demod_type evaluation in tuner_attach_probe() to a switch-case instead of an if() for each possible value. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 11 +++ drivers/media/pci/ngene/ngene.h | 3 +++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 1de8cbee..065b83ee569b 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -123,10 +123,13 @@ static int tuner_attach_tda18271(struct ngene_channel *chan) static int tuner_attach_probe(struct ngene_channel *chan) { - if (chan->demod_type == 0) + switch (chan->demod_type) { + case DEMOD_TYPE_STV090X: return tuner_attach_stv6110(chan); - if (chan->demod_type == 1) + case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); + } + return -EINVAL; } @@ -251,7 +254,7 @@ static int cineS2_probe(struct ngene_channel *chan) i2c = &chan->dev->channel[1].i2c_adapter; if (port_has_stv0900(i2c, chan->number)) { - chan->demod_type = 0; + chan->demod_type = DEMOD_TYPE_STV090X; fe_conf = chan->dev->card_info->fe_config[chan->number]; /* demod found, attach it */ rc = demod_attach_stv0900(chan); @@ -280,7 +283,7 @@ static int cineS2_probe(struct ngene_channel *chan) return -EIO; } } else if (port_has_drxk(i2c, chan->number^2)) { - chan->demod_type = 1; + chan->demod_type = DEMOD_TYPE_DRXK; demod_attach_drxk(chan, i2c); } else { dev_err(pdev, "No demod found on chan %d\n", chan->number); diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index caf8602c7459..9724701a3274 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -51,6 +51,9 @@ #define VIDEO_CAP_MPEG4 512 #endif +#define DEMOD_TYPE_STV090X 0 +#define DEMOD_TYPE_DRXK1 + enum STREAM { STREAM_VIDEOIN1 = 0,/* ITU656 or TS Input */ STREAM_VIDEOIN2, -- 2.16.1
[PATCH v2 07/12] [media] ngene: add support for DuoFlex S2 V4 addon modules
From: Daniel Scheller Add support for the STV0910/STV6111/LNBH25 based DuoFlex S2 V4 DVB-S2 addon modules by recognizing them from their XO2 type value and using the auxiliary stv0910, stv6111 and lnbh25 driver to form a complete DVB frontend. This also adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the STV0910, STV6111 and LNBH25 demod/tuner/LNB-IC drivers to Kconfig. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/Kconfig | 3 ++ drivers/media/pci/ngene/ngene-cards.c | 83 +++ 2 files changed, 86 insertions(+) diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index f717567f54a5..e06d019996f3 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -11,6 +11,9 @@ config DVB_NGENE select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV0910 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index cdc8db14c606..00b100660784 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -46,6 +46,9 @@ #include "stv0367_priv.h" #include "tda18212.h" #include "cxd2841er.h" +#include "stv0910.h" +#include "stv6111.h" +#include "lnbh25.h" // /* I2C transfer functions used for demod/tuner probing***/ @@ -152,6 +155,30 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) return 0; } +static int tuner_attach_stv6111(struct ngene_channel *chan) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct i2c_adapter *i2c; + struct dvb_frontend *fe; + u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); + + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + i2c = &chan->dev->channel[0].i2c_adapter; + else + i2c = &chan->dev->channel[1].i2c_adapter; + + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); + if (!fe) { + fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); + if (!fe) { + dev_err(pdev, "stv6111_attach() failed!\n"); + return -ENODEV; + } + } + return 0; +} + static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) { struct ngene_channel *chan = fe->sec_priv; @@ -283,6 +310,8 @@ static int tuner_attach_probe(struct ngene_channel *chan) case DEMOD_TYPE_SONY_C2T2: case DEMOD_TYPE_SONY_C2T2I: return tuner_attach_tda18212(chan, chan->demod_type); + case DEMOD_TYPE_STV0910: + return tuner_attach_stv6111(chan); } return -EINVAL; @@ -326,6 +355,54 @@ static int demod_attach_stv0900(struct ngene_channel *chan) return 0; } +static struct stv0910_cfg stv0910_p = { + .adr = 0x68, + .parallel = 1, + .rptlvl = 4, + .clk = 3000, +}; + +static struct lnbh25_config lnbh25_cfg = { + .i2c_address = 0x0c << 1, + .data2_config = LNBH25_TEN +}; + +static int demod_attach_stv0910(struct ngene_channel *chan, + struct i2c_adapter *i2c) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct stv0910_cfg cfg = stv0910_p; + struct lnbh25_config lnbcfg = lnbh25_cfg; + + chan->fe = dvb_attach(stv0910_attach, i2c, &cfg, (chan->number & 1)); + if (!chan->fe) { + cfg.adr = 0x6c; + chan->fe = dvb_attach(stv0910_attach, i2c, + &cfg, (chan->number & 1)); + } + if (!chan->fe) { + dev_err(pdev, "stv0910_attach() failed!\n"); + return -ENODEV; + } + + /* +* attach lnbh25 - leftshift by one as the lnbh25 driver expects 8bit +* i2c addresses +*/ + lnbcfg.i2c_address = (((chan->number & 1) ? 0x0d : 0x0c) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + lnbcfg.i2c_address = (((chan->number & 1) ? 0x09 : 0x08) << 1); + if (!dvb_attach(lnbh25_attach, chan->fe, &lnbcfg, i2c)) { + dev_err(pdev, "lnbh25_attach() failed!\n&
[PATCH v2 10/12] [media] ngene: don't treat non-existing demods as error
From: Daniel Scheller When probing the I2C busses in cineS2_probe(), it's no error when there's no hardware connected to the probed expansion connector, so print this informal message with info severity. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index d603d0af703e..37e9f0eb6d20 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -728,7 +728,7 @@ static int cineS2_probe(struct ngene_channel *chan) dev_info(pdev, "STV0367 on channel %d\n", chan->number); demod_attach_stv0367(chan, i2c); } else { - dev_err(pdev, "No demod found on chan %d\n", chan->number); + dev_info(pdev, "No demod found on chan %d\n", chan->number); return -ENODEV; } return 0; -- 2.16.1
[PATCH v2 12/12] [media] ngene: compensate for TS buffer offset shifts
From: Daniel Scheller A possible hardware bug was discovered when using CA addon hardware attached to the ngene hardware, in that the TS input buffer much likely will shift and thus become unaligned to 188 byte blocks (a full TS frame) when things like CA module initialisation (which happens via differing communication paths) take place. This causes the TS NULL removal in tsin_exchange() to fail to detect this previously inserted data and thus causes userspace applications to receive data they didn't sent beforehand and ultimately cause troubles. On driver load with an inserted CAM, buffers are fine at first (note that the driver has to keep the communication running from/to the card by inserting TS NULL frames, this is done in tsout_exchange() via FillTSBuffer() - that data is simply sent back by the hardware): offset | 01 2 3 4 5 188 189 190 191 192 193 376 data | 47 1f ff 10 6f 6f 47 1f ff 10 6f 6f 47 After a few seconds, the CA module is recognised and initialised, which is signalled by dvb_ca_en50221: dvb_ca adapter X: DVB CAM detected and initialised successfully This is where the first shift happens (this is always four bytes), buffer becomes like this: offset | 01 2 3 4 5 188 189 190 191 192 193 376 data | 6f 6f 6f 6f 47 1f 6f 6f 6f 6f 47 1f 6f Next, VDR, TVHeadend or any other CI aware application is started, buffers will shift by even more bytes. It is believed this is due to the hardware not handling control and data bytes properly distinct, and control data having an influence on the actual data stream, which we cannot properly detect at the driver level. Workaround this hardware quirk by adding a detection for the TS sync byte 0x47 before each TS frame copy, scan for a new SYNC byte and a TS NULL packet if buffers become unaligned, take note of that offset and apply that when copying data to the DVB ring buffers. The last <188 bytes from the hardware buffers are stored in a temp buffer (tsin_buffer), for which the remainder will be in the beginning of the next hardware buffer (next iteration of tsin_exchange()). That remainder will be appended to the temp buffer and finally sent to the DVB ring buffer. The resulting TS stream is perfectly fine, and the TS NULL packets inserted by the driver which are sent back are properly removed. The resulting offset is being clamped to 188 byte segments (one TS packet). Though this can result in a repeated TS packet if the overall offset grows beyond this (and it will grow only on CA initialisation), this is still way better than unaligned TS frames and data sent to userspace that just isn't supposed to be there. This compensation can be toggled by the ci_tsfix modparam, which defaults to 1 (enabled). In the case of problems, this can be turned off by setting the parameter to 0 to restore the old behaviour. Signed-off-by: Daniel Scheller --- Changes since v1: - TS buffer offset correction missed a check for the remaining buffer length before copying the next full 188-byte block, which might could have caused out-of-bound-reads from void *buf. Also, tsin_find_offset returns it's offset clamped to 188 byte boundaries to not accidentally skip over valid TS data. Few typos in the commit message were fixed and a note for the modparam was added, too. drivers/media/pci/ngene/ngene-dvb.c | 91 - drivers/media/pci/ngene/ngene.h | 3 ++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 6d72b9f69418..0f9759a4d124 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -38,6 +38,9 @@ #include "ngene.h" +static int ci_tsfix = 1; +module_param(ci_tsfix, int, 0444); +MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)"); // /* COMMAND API interface / @@ -123,6 +126,24 @@ static u32 overflow; static u32 stripped; #endif +static int tsin_find_offset(void *buf, u32 len) +{ + int i, l; + + l = len - sizeof(fill_ts); + if (l <= 0) + return -1; + + for (i = 0; i < l; i++) { + if (((char *)buf)[i] == 0x47) { + if (!memcmp(buf + i, fill_ts, sizeof(fill_ts))) + return i % 188; + } + } + + return -1; +} + static inline void tsin_copy_stripped(struct ngene *dev, void *buf) { if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { @@ -153,18 +174,86 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; struct ngene *dev = chan-&g
[PATCH v2 08/12] [media] ngene: deduplicate I2C adapter evaluation
From: Daniel Scheller The I2C adapter evaluation (based on chan->number) is duplicated at several places (tuner_attach_() functions, demod_attach_stv0900() and cineS2_probe()). Clean this up by wrapping that construct in a separate function which all users of that can pass the ngene_channel pointer and get the correct I2C adapter from. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 41 +-- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 00b100660784..dff55c7c9f86 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -118,17 +118,25 @@ static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) /* Demod/tuner attachment ***/ // +static struct i2c_adapter *i2c_adapter_from_chan(struct ngene_channel *chan) +{ + /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ + if (chan->number < 2) + return &chan->dev->channel[0].i2c_adapter; + + return &chan->dev->channel[1].i2c_adapter; +} + static int tuner_attach_stv6110(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; struct stv6110x_config *tunerconf = (struct stv6110x_config *) chan->dev->card_info->tuner_config[chan->number]; const struct stv6110x_devctl *ctl; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ if (chan->number < 2) i2c = &chan->dev->channel[0].i2c_adapter; else @@ -158,16 +166,10 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) static int tuner_attach_stv6111(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; u8 adr = 4 + ((chan->number & 1) ? 0x63 : 0x60); - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr); if (!fe) { fe = dvb_attach(stv6111_attach, chan->fe, i2c, adr & ~4); @@ -197,10 +199,9 @@ static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) static int tuner_attach_tda18271(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct dvb_frontend *fe; - i2c = &chan->dev->channel[0].i2c_adapter; if (chan->fe->ops.i2c_gate_ctrl) chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); @@ -240,7 +241,7 @@ static int tuner_tda18212_ping(struct ngene_channel *chan, static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct i2c_client *client; struct tda18212_config config = { .fe = chan->fe, @@ -262,12 +263,6 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) else board_info.addr = 0x60; - /* tuner 1+2: i2c adapter #0, tuner 3+4: i2c adapter #1 */ - if (chan->number < 2) - i2c = &chan->dev->channel[0].i2c_adapter; - else - i2c = &chan->dev->channel[1].i2c_adapter; - /* * due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when @@ -320,7 +315,7 @@ static int tuner_attach_probe(struct ngene_channel *chan) static int demod_attach_stv0900(struct ngene_channel *chan) { struct device *pdev = &chan->dev->pci_dev->dev; - struct i2c_adapter *i2c; + struct i2c_adapter *i2c = i2c_adapter_from_chan(chan); struct stv090x_config *feconf = (struct stv090x_config *) chan->dev->card_info->fe_config[chan->number]; @@ -620,7 +615,7 @@ static int port_has_xo
[PATCH v2 09/12] [media] ngene: check for CXD2099AR presence before attaching
From: Daniel Scheller Currently, if there's no CXD2099AR attached to any expansion connector of the ngene hardware, it will complain with this on every module load: cxd2099 1-0040: No CXD2099AR detected at 0x40 cxd2099: probe of 1-0040 failed with error -5 ngene :02:00.0: CXD2099AR attach failed This happens due to the logic assuming such hardware is always there and blindly tries to attach the cxd2099 I2C driver. Rather add a probe function (in ngene-cards.c with a prototype in ngene.h) to check for the existence of such hardware before probing, and don't try further if no CXD2099 was found. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 19 +++ drivers/media/pci/ngene/ngene-core.c | 14 ++ drivers/media/pci/ngene/ngene.h | 3 +++ 3 files changed, 36 insertions(+) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index dff55c7c9f86..d603d0af703e 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -505,6 +505,25 @@ static int port_has_stv0367(struct i2c_adapter *i2c) return 1; } +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type) +{ + u8 val; + u8 probe[4] = { 0xe0, 0x00, 0x00, 0x00 }, data[4]; + struct i2c_msg msgs[2] = {{ .addr = 0x40, .flags = 0, + .buf = probe, .len = 4 }, + { .addr = 0x40, .flags = I2C_M_RD, + .buf = data, .len = 4 } }; + val = i2c_transfer(i2c, msgs, 2); + if (val != 2) + return 0; + + if (data[0] == 0x02 && data[1] == 0x2b && data[3] == 0x43) + *type = 2; + else + *type = 1; + return 1; +} + static int demod_attach_drxk(struct ngene_channel *chan, struct i2c_adapter *i2c) { diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index 526d0adfa427..f69a8fc1ec2a 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1589,6 +1589,20 @@ static void cxd_attach(struct ngene *dev) .addr = 0x40, .platform_data = &cxd_cfg, }; + int ret; + u8 type; + + /* check for CXD2099AR presence before attaching */ + ret = ngene_port_has_cxd2099(&dev->channel[0].i2c_adapter, &type); + if (!ret) { + dev_dbg(pdev, "No CXD2099AR found\n"); + return; + } + + if (type != 1) { + dev_warn(pdev, "CXD2099AR is uninitialized!\n"); + return; + } cxd_cfg.en = &ci->en; diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h index 72195f6552b3..66d8eaa28549 100644 --- a/drivers/media/pci/ngene/ngene.h +++ b/drivers/media/pci/ngene/ngene.h @@ -909,6 +909,9 @@ int ngene_command_gpio_set(struct ngene *dev, u8 select, u8 level); void set_transfer(struct ngene_channel *chan, int state); void FillTSBuffer(void *Buffer, int Length, u32 Flags); +/* Provided by ngene-cards.c */ +int ngene_port_has_cxd2099(struct i2c_adapter *i2c, u8 *type); + /* Provided by ngene-i2c.c */ int ngene_i2c_init(struct ngene *dev, int dev_nr); -- 2.16.1
[PATCH v2 11/12] [media] ngene: move the tsin_exchange() stripcopy block into a function
From: Daniel Scheller Move the copy logic that will skip previously inserted TS NULL frames when moving data to the DVB ring buffers into an own function. This is done to not duplicate code all over the place with the following TS offset shift fixup patch. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-dvb.c | 48 + 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index f71fd41c762c..6d72b9f69418 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -123,6 +123,32 @@ static u32 overflow; static u32 stripped; #endif +static inline void tsin_copy_stripped(struct ngene *dev, void *buf) +{ + if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); +#ifdef DEBUG_CI_XFER + ok++; +#endif + } +#ifdef DEBUG_CI_XFER + else + overflow++; +#endif + } +#ifdef DEBUG_CI_XFER + else + stripped++; + + if (ok % 100 == 0 && overflow) + dev_warn(&dev->pci_dev->dev, +"%s: ok %u overflow %u dropped %u\n", +__func__, ok, overflow, stripped); +#endif +} + void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; @@ -134,28 +160,8 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) if (dev->ci.en && chan->number == 2) { while (len >= 188) { - if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); - wake_up(&dev->tsin_rbuf.queue); -#ifdef DEBUG_CI_XFER - ok++; -#endif - } -#ifdef DEBUG_CI_XFER - else - overflow++; -#endif - } -#ifdef DEBUG_CI_XFER - else - stripped++; + tsin_copy_stripped(dev, buf); - if (ok % 100 == 0 && overflow) - dev_warn(&dev->pci_dev->dev, -"%s: ok %u overflow %u dropped %u\n", -__func__, ok, overflow, stripped); -#endif buf += 188; len -= 188; } -- 2.16.1
[PATCH v2 06/12] [media] ngene: add support for Sony CXD28xx-based DuoFlex modules
From: Daniel Scheller Recognize (probe) and support (attach) all Sony CXD28xx based DuoFlex addon modules/cards, namely the DuoFlex CT2 (CXD2837), ISDB-T (CXD2838), C2T2 (CXD2843) and C2T2I (CXD2854). Since all these modules are equipped with a MachXO2 interface, that support is required for the hardware to work. This functionality utilises the auxiliary cxd2841er and tda18212 drivers. This also adds autoselection (if MEDIA_SUBDRV_AUTOSELECT) of the CXD2841ER demod driver to Kconfig. The __maybe_unused annotation can now be removed from the xo2names array. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/Kconfig | 1 + drivers/media/pci/ngene/ngene-cards.c | 63 --- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index c3254f9dc8ad..f717567f54a5 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -9,6 +9,7 @@ config DVB_NGENE select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT + select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT ---help--- diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 05b8e56999ec..cdc8db14c606 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -45,6 +45,7 @@ #include "stv0367.h" #include "stv0367_priv.h" #include "tda18212.h" +#include "cxd2841er.h" // /* I2C transfer functions used for demod/tuner probing***/ @@ -277,6 +278,10 @@ static int tuner_attach_probe(struct ngene_channel *chan) case DEMOD_TYPE_DRXK: return tuner_attach_tda18271(chan); case DEMOD_TYPE_STV0367: + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: + case DEMOD_TYPE_SONY_C2T2: + case DEMOD_TYPE_SONY_C2T2I: return tuner_attach_tda18212(chan, chan->demod_type); } @@ -358,6 +363,34 @@ static int demod_attach_stv0367(struct ngene_channel *chan, return 0; } +static int demod_attach_cxd28xx(struct ngene_channel *chan, + struct i2c_adapter *i2c, int osc24) +{ + struct device *pdev = &chan->dev->pci_dev->dev; + struct cxd2841er_config cfg; + + /* the cxd2841er driver expects 8bit/shifted I2C addresses */ + cfg.i2c_addr = ((chan->number & 1) ? 0x6d : 0x6c) << 1; + + cfg.xtal = osc24 ? SONY_XTAL_24000 : SONY_XTAL_20500; + cfg.flags = CXD2841ER_AUTO_IFHZ | CXD2841ER_EARLY_TUNE | + CXD2841ER_NO_WAIT_LOCK | CXD2841ER_NO_AGCNEG | + CXD2841ER_TSBITS | CXD2841ER_TS_SERIAL; + + /* attach frontend */ + chan->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); + + if (!chan->fe) { + dev_err(pdev, "CXD28XX attach failed!\n"); + return -ENODEV; + } + + chan->fe->sec_priv = chan; + chan->gate_ctrl = chan->fe->ops.i2c_gate_ctrl; + chan->fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; + return 0; +} + static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) { struct ngene_channel *chan = fe->analog_demod_priv; @@ -426,7 +459,7 @@ static int demod_attach_drxk(struct ngene_channel *chan, /* XO2 related lists and functions **/ // -static char __maybe_unused *xo2names[] = { +static char *xo2names[] = { "DUAL DVB-S2", "DUAL DVB-C/T/T2", "DUAL DVB-ISDBT", @@ -513,7 +546,8 @@ static int cineS2_probe(struct ngene_channel *chan) struct i2c_adapter *i2c; struct stv090x_config *fe_conf; u8 buf[3]; - u8 xo2_type, xo2_id; + u8 xo2_type, xo2_id, xo2_demodtype; + u8 sony_osc24 = 0; struct i2c_msg i2c_msg = { .flags = 0, .buf = buf }; int rc; @@ -537,9 +571,28 @@ static int cineS2_probe(struct ngene_channel *chan) else init_xo2(chan, i2c); - /* TODO: implement support for XO2 module types */ - dev_warn(pdev, "XO2 not supported\n"); - return -ENODEV; + xo2_demodtype = DEMOD_TYPE_XO2 + xo2_id; + + switch (xo2_demodtype) { + case DEMOD_TYPE_SONY_CT2: + case DEMOD_TYPE_SONY_ISDBT: +
[PATCH] [media] ngene: add proper polling to the dvbdev_ci file ops
From: Daniel Scheller Implement the poll callback for the dvbdev_ci file ops. The ts_poll() function queries the DVB ring buffers for available data and space, and reports this as appropriate. Also, set the dvb_device readers, writers and users to proper values (one reader, one writer, two users). This fixes the raw CI TS transport in conjunction with TVheadend's DDCI functionality. Signed-off-by: Daniel Scheller --- This patch was committed ontop of the ngene hardware/tsfix series, so it might conflict if that series isn't applied beforehand (I honestly didn't test that). drivers/media/pci/ngene/ngene-dvb.c | 29 ++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 0f9759a4d124..2df641e05fca 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -87,18 +87,41 @@ static ssize_t ts_read(struct file *file, char __user *buf, return count; } +static __poll_t ts_poll(struct file *file, poll_table *wait) +{ + struct dvb_device *dvbdev = file->private_data; + struct ngene_channel *chan = dvbdev->priv; + struct ngene *dev = chan->dev; + struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf; + struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf; + __poll_t mask = 0; + + poll_wait(file, &rbuf->queue, wait); + poll_wait(file, &wbuf->queue, wait); + + if (!dvb_ringbuffer_empty(rbuf)) + mask |= EPOLLIN | EPOLLRDNORM; + if (dvb_ringbuffer_free(wbuf) >= 188) + mask |= EPOLLOUT | EPOLLWRNORM; + + return mask; +} + static const struct file_operations ci_fops = { .owner = THIS_MODULE, .read= ts_read, .write = ts_write, .open= dvb_generic_open, .release = dvb_generic_release, + .poll= ts_poll, + .mmap= NULL, }; struct dvb_device ngene_dvbdev_ci = { - .readers = -1, - .writers = -1, - .users = -1, + .priv= NULL, + .readers = 1, + .writers = 1, + .users = 2, .fops= &ci_fops, }; -- 2.16.1
[PATCH 0/4] cxd2099 series fixup
From: Daniel Scheller These are the missing bits from the cxd2099 that went MIA during the merge of the series. Please pull - ngene driver requires the ngene patch for all I2C clients to work (including the tda18212 that's now used since the merge of the other ngene series) and ddbridge can't make use of the cxd2099 driver at all right now. Daniel Scheller (3): [media] ddbridge: adapt cxd2099 attach to new i2c_client way [media] ngene: add I2C_FUNC_I2C to the I2C interface functionality [media] dvb-frontends/cxd2099: remove remainders from old attach way Jasmin Jessich (1): [media] MAINTAINERS: add entry for cxd2099 MAINTAINERS | 8 + drivers/media/dvb-frontends/cxd2099.h| 10 -- drivers/media/pci/ddbridge/ddbridge-ci.c | 62 +--- drivers/media/pci/ddbridge/ddbridge.h| 1 + drivers/media/pci/ngene/ngene-i2c.c | 2 +- 5 files changed, 67 insertions(+), 16 deletions(-) -- 2.16.1
[PATCH 4/4] [media] MAINTAINERS: add entry for cxd2099
From: Jasmin Jessich The cxd2099 driver is now maintained and being taken care of by * Jasmin Jessich Signed-off-by: Jasmin Jessich --- MAINTAINERS | 8 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 0eea2f0e9456..298f0b84a4ed 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8612,6 +8612,14 @@ T: git git://linuxtv.org/media_tree.git S: Supported F: drivers/media/dvb-frontends/ascot2e* +MEDIA DRIVERS FOR CXD2099AR CI CONTROLLERS +M: Jasmin Jessich +L: linux-media@vger.kernel.org +W: https://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/dvb-frontends/cxd2099* + MEDIA DRIVERS FOR CXD2841ER M: Sergey Kozlov M: Abylay Ospan -- 2.16.1
[PATCH 1/4] [media] ddbridge: adapt cxd2099 attach to new i2c_client way
From: Daniel Scheller Change the way the cxd2099 hardware is being attached to the new I2C client interface way. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/pci/ddbridge/ddbridge-ci.c | 62 +--- drivers/media/pci/ddbridge/ddbridge.h| 1 + 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index ed19890710d6..6585ef54ac22 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -172,6 +172,7 @@ static void ci_attach(struct ddb_port *port) memcpy(&ci->en, &en_templ, sizeof(en_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; } @@ -304,6 +305,7 @@ static void ci_xo2_attach(struct ddb_port *port) memcpy(&ci->en, &en_xo2_templ, sizeof(en_xo2_templ)); ci->en.data = ci; port->en = &ci->en; + port->en_freedata = 1; ci->port = port; ci->nr = port->nr - 2; ci->port->creg = 0; @@ -311,20 +313,58 @@ static void ci_xo2_attach(struct ddb_port *port) write_creg(ci, 0x08, 0x08); } -static struct cxd2099_cfg cxd_cfg = { +static const struct cxd2099_cfg cxd_cfgtmpl = { .bitrate = 72000, - .adr = 0x40, .polarity = 1, .clock_mode = 1, .max_i2c = 512, }; +static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) +{ + struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; + struct i2c_client *client; + struct i2c_board_info board_info = { + .type = "cxd2099", + .addr = 0x40, + .platform_data = &cxd_cfg, + }; + + cxd_cfg.bitrate = bitrate; + cxd_cfg.en = &port->en; + + request_module(board_info.type); + + client = i2c_new_device(&port->i2c->adap, &board_info); + if (!client || !client->dev.driver) + goto err_ret; + + if (!try_module_get(client->dev.driver->owner)) + goto err_i2c; + + if (!port->en) + goto err_i2c; + + port->dvb[0].i2c_client[0] = client; + port->en_freedata = 0; + return 0; + +err_i2c: + i2c_unregister_device(client); +err_ret: + dev_err(port->dev->dev, "CXD2099AR attach failed\n"); + return -ENODEV; +} + int ddb_ci_attach(struct ddb_port *port, u32 bitrate) { + int ret; + switch (port->type) { case DDB_CI_EXTERNAL_SONY: - cxd_cfg.bitrate = bitrate; - port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); + ret = ci_cxd2099_attach(port, bitrate); + if (ret) + return -ENODEV; break; case DDB_CI_EXTERNAL_XO2: case DDB_CI_EXTERNAL_XO2_B: @@ -345,11 +385,23 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { + struct i2c_client *client; + if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - kfree(port->en->data); + + client = port->dvb[0].i2c_client[0]; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* free alloc'ed memory if needed */ + if (port->en_freedata) + kfree(port->en->data); + port->en = NULL; } } diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h index 095457737bc1..f223dc6c9963 100644 --- a/drivers/media/pci/ddbridge/ddbridge.h +++ b/drivers/media/pci/ddbridge/ddbridge.h @@ -276,6 +276,7 @@ struct ddb_port { struct ddb_input *input[2]; struct ddb_output *output; struct dvb_ca_en50221 *en; + u8 en_freedata; struct ddb_dvb dvb[2]; u32gap; u32obr; -- 2.16.1
[PATCH 2/4] [media] ngene: add I2C_FUNC_I2C to the I2C interface functionality
From: Daniel Scheller Report I2C_FUNC_I2C in .functionality() aswell. The I2C interface can handle this fine and even is required for all I2C client drivers that utilise the regmap API which are used from within the ngene driver. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/pci/ngene/ngene-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-i2c.c b/drivers/media/pci/ngene/ngene-i2c.c index 3004947f300b..092d46c2a3a9 100644 --- a/drivers/media/pci/ngene/ngene-i2c.c +++ b/drivers/media/pci/ngene/ngene-i2c.c @@ -147,7 +147,7 @@ static int ngene_i2c_master_xfer(struct i2c_adapter *adapter, static u32 ngene_i2c_functionality(struct i2c_adapter *adap) { - return I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm ngene_i2c_algo = { -- 2.16.1
[PATCH 3/4] [media] dvb-frontends/cxd2099: remove remainders from old attach way
From: Daniel Scheller As all drivers using the cxd2099 are converted to handle attach/detach the generic I2C client way, the static inline cxd2099_attach isn't required anymore. Thus cleanup cxd2099.h from the remainders, the adr struct member isn't used anymore aswell. Signed-off-by: Daniel Scheller Signed-off-by: Jasmin Jessich --- drivers/media/dvb-frontends/cxd2099.h | 10 -- 1 file changed, 10 deletions(-) diff --git a/drivers/media/dvb-frontends/cxd2099.h b/drivers/media/dvb-frontends/cxd2099.h index 679e87512799..8fa45a4c615a 100644 --- a/drivers/media/dvb-frontends/cxd2099.h +++ b/drivers/media/dvb-frontends/cxd2099.h @@ -20,7 +20,6 @@ struct cxd2099_cfg { u32 bitrate; - u8 adr; u8 polarity; u8 clock_mode; @@ -30,13 +29,4 @@ struct cxd2099_cfg { struct dvb_ca_en50221 **en; }; -/* TODO: remove when done */ -static inline struct -dvb_ca_en50221 *cxd2099_attach(struct cxd2099_cfg *cfg, void *priv, - struct i2c_adapter *i2c) -{ - dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - #endif -- 2.16.1
[PATCH 0/2] ngene CI TS fixup
From: Daniel Scheller Remainder of the ngene updates series, taking care of the TS buffer offset shift which occurs in conjunction with CICAM hardware during CAM inits. Changed as requested to get rid of the DEBUG_CI_XFER ifdeffery. This might aswell be considered a v3 of [1], but as 10 of 12 patches were merged already, these two patches can be treated separate. [1] https://www.spinics.net/lists/linux-media/msg129606.html Daniel Scheller (2): [media] ngene: move the tsin_exchange() stripcopy block into a function [media] ngene: compensate for TS buffer offset shifts drivers/media/pci/ngene/ngene-dvb.c | 126 drivers/media/pci/ngene/ngene.h | 3 + 2 files changed, 102 insertions(+), 27 deletions(-) -- 2.16.1
[PATCH 1/2] [media] ngene: move the tsin_exchange() stripcopy block into a function
From: Daniel Scheller Move the copy logic that will skip previously inserted TS NULL frames when moving data to the DVB ring buffers into an own function. This is done to not duplicate code all over the place with the following TS offset shift fixup patch. While we're touching this part of the code, get rid of the DEBUG_CI_XFER debug-ifdeffery. This could be toggleable either by a Kconfig or a module param, but in the end this will accidentally be enabled and cause lots of kernel log messages, and such devel debug shouldn't be there anyway. Signed-off-by: Daniel Scheller --- Changed since https://www.spinics.net/lists/linux-media/msg129616.html: * DEBUG_CI_XFER ifdeffery removed drivers/media/pci/ngene/ngene-dvb.c | 39 +++-- 1 file changed, 11 insertions(+), 28 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 65c79f1b36f7..93a07a370cfd 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -139,12 +139,15 @@ static void swap_buffer(u32 *p, u32 len) /* start of filler packet */ static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; -/* #define DEBUG_CI_XFER */ -#ifdef DEBUG_CI_XFER -static u32 ok; -static u32 overflow; -static u32 stripped; -#endif +static inline void tsin_copy_stripped(struct ngene *dev, void *buf) +{ + if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { + if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { + dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); + wake_up(&dev->tsin_rbuf.queue); + } + } +} void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { @@ -157,28 +160,8 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) if (dev->ci.en && chan->number == 2) { while (len >= 188) { - if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) { - if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) { - dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188); - wake_up(&dev->tsin_rbuf.queue); -#ifdef DEBUG_CI_XFER - ok++; -#endif - } -#ifdef DEBUG_CI_XFER - else - overflow++; -#endif - } -#ifdef DEBUG_CI_XFER - else - stripped++; - - if (ok % 100 == 0 && overflow) - dev_warn(&dev->pci_dev->dev, -"%s: ok %u overflow %u dropped %u\n", -__func__, ok, overflow, stripped); -#endif + tsin_copy_stripped(dev, buf); + buf += 188; len -= 188; } -- 2.16.1
[PATCH 2/2] [media] ngene: compensate for TS buffer offset shifts
From: Daniel Scheller A possible hardware bug was discovered when using CA addon hardware attached to the ngene hardware, in that the TS input buffer much likely will shift and thus become unaligned to 188 byte blocks (a full TS frame) when things like CA module initialisation (which happens via differing communication paths) take place. This causes the TS NULL removal in tsin_exchange() to fail to detect this previously inserted data and thus causes userspace applications to receive data they didn't sent beforehand and ultimately cause troubles. On driver load with an inserted CAM, buffers are fine at first (note that the driver has to keep the communication running from/to the card by inserting TS NULL frames, this is done in tsout_exchange() via FillTSBuffer() - that data is simply sent back by the hardware): offset | 01 2 3 4 5 188 189 190 191 192 193 376 data | 47 1f ff 10 6f 6f 47 1f ff 10 6f 6f 47 After a few seconds, the CA module is recognised and initialised, which is signalled by dvb_ca_en50221: dvb_ca adapter X: DVB CAM detected and initialised successfully This is where the first shift happens (this is always four bytes), buffer becomes like this: offset | 01 2 3 4 5 188 189 190 191 192 193 376 data | 6f 6f 6f 6f 47 1f 6f 6f 6f 6f 47 1f 6f Next, VDR, TVHeadend or any other CI aware application is started, buffers will shift by even more bytes. It is believed this is due to the hardware not handling control and data bytes properly distinct, and control data having an influence on the actual data stream, which we cannot properly detect at the driver level. Workaround this hardware quirk by adding a detection for the TS sync byte 0x47 before each TS frame copy, scan for a new SYNC byte and a TS NULL packet if buffers become unaligned, take note of that offset and apply that when copying data to the DVB ring buffers. The last <188 bytes from the hardware buffers are stored in a temp buffer (tsin_buffer), for which the remainder will be in the beginning of the next hardware buffer (next iteration of tsin_exchange()). That remainder will be appended to the temp buffer and finally sent to the DVB ring buffer. The resulting TS stream is perfectly fine, and the TS NULL packets inserted by the driver which are sent back are properly removed. The resulting offset is being clamped to 188 byte segments (one TS packet). Though this can result in a repeated TS packet if the overall offset grows beyond this (and it will grow only on CA initialisation), this is still way better than unaligned TS frames and data sent to userspace that just isn't supposed to be there. This compensation can be toggled by the ci_tsfix modparam, which defaults to 1 (enabled). In the case of problems, this can be turned off by setting the parameter to 0 to restore the old behaviour. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-dvb.c | 91 - drivers/media/pci/ngene/ngene.h | 3 ++ 2 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/media/pci/ngene/ngene-dvb.c b/drivers/media/pci/ngene/ngene-dvb.c index 93a07a370cfd..fee89b9ed9c1 100644 --- a/drivers/media/pci/ngene/ngene-dvb.c +++ b/drivers/media/pci/ngene/ngene-dvb.c @@ -38,6 +38,9 @@ #include "ngene.h" +static int ci_tsfix = 1; +module_param(ci_tsfix, int, 0444); +MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifs in conjunction with CI expansions (default: 1/enabled)"); // /* COMMAND API interface / @@ -139,6 +142,24 @@ static void swap_buffer(u32 *p, u32 len) /* start of filler packet */ static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER }; +static int tsin_find_offset(void *buf, u32 len) +{ + int i, l; + + l = len - sizeof(fill_ts); + if (l <= 0) + return -1; + + for (i = 0; i < l; i++) { + if (((char *)buf)[i] == 0x47) { + if (!memcmp(buf + i, fill_ts, sizeof(fill_ts))) + return i % 188; + } + } + + return -1; +} + static inline void tsin_copy_stripped(struct ngene *dev, void *buf) { if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) { @@ -153,18 +174,86 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags) { struct ngene_channel *chan = priv; struct ngene *dev = chan->dev; - + int tsoff; if (flags & DF_SWAP32) swap_buffer(buf, len); if (dev->ci.en && chan->number == 2) { + /* blindly copy buffers if ci_tsfix is disabled */ + if (!ci_tsfix) { + while (len >= 188
[PATCH 3/4] [media] ddbridge: use common DVB I2C client handling helpers
From: Daniel Scheller Instead of keeping duplicated I2C client handling construct, make use of the newly introduced dvb_module_*() helpers. This not only keeps things way cleaner and removes the need for duplicated I2C client attach code, but even allows to get rid of some variables that won't help in making things look cleaner anymore. The check on a valid ptr on port->en isn't really needed since the cxd2099 driver will set it at a time where it is going to return successfully from probing. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-ci.c | 33 ++ drivers/media/pci/ddbridge/ddbridge-core.c | 37 +++--- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 6585ef54ac22..d0ce6a1f1bd0 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -324,34 +324,20 @@ static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) { struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; - struct i2c_board_info board_info = { - .type = "cxd2099", - .addr = 0x40, - .platform_data = &cxd_cfg, - }; cxd_cfg.bitrate = bitrate; cxd_cfg.en = &port->en; - request_module(board_info.type); - - client = i2c_new_device(&port->i2c->adap, &board_info); - if (!client || !client->dev.driver) - goto err_ret; - - if (!try_module_get(client->dev.driver->owner)) - goto err_i2c; - - if (!port->en) - goto err_i2c; + client = dvb_module_probe("cxd2099", "cxd2099", &port->i2c->adap, + 0x40, &cxd_cfg); + if (!client) + goto err; port->dvb[0].i2c_client[0] = client; port->en_freedata = 0; return 0; -err_i2c: - i2c_unregister_device(client); -err_ret: +err: dev_err(port->dev->dev, "CXD2099AR attach failed\n"); return -ENODEV; } @@ -385,18 +371,13 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { - struct i2c_client *client; - if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - client = port->dvb[0].i2c_client[0]; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } + dvb_module_release(port->dvb[0].i2c_client[0]); + port->dvb[0].i2c_client[0] = NULL; /* free alloc'ed memory if needed */ if (port->en_freedata) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index f9bee36f1cad..36d2deb1c106 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -999,37 +999,22 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (input->nr & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (input->nr & 1) ? 0x63 : 0x60; /* due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when * cold started, or it very likely will fail. */ if (porttype == DDB_TUNER_DVBCT_ST) - tuner_tda18212_ping(input, board_info.addr); - - request_module(board_info.type); - - /* perform tuner init/attach */ - client = i2c_new_device(adapter, &board_info); - if (!client || !client->dev.driver) - goto err; + tuner_tda18212_ping(input, addr); - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", "tda18212", + adapter, addr, &config); + if (!client) goto err; - } dvb->i2c_client[0] = client; - return 0; err: dev_err(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); @@ -1253,7 +1238,6 @@ static void dvb_input_detach(struct ddb_input *input) {
[PATCH 0/4] misc cxd2099/Kconfig/ddbridge/ngene improvements
From: Daniel Scheller This series improves this: * The cxd2099 Kconfig block is improved to be more complete and to match those of the other drivers * The sp2 CI driver is moved down to the new CI EN50221 subsection in the Kconfig of the dvb-frontends/ subdir * Both ddbridge's and ngene's I2C client handling is cleaned up to make use of the new dvb_module_*() I2C handling helpers. Daniel Scheller (4): [media] dvb-frontends/cxd2099: Kconfig additions [media] dvb-frontends/Kconfig: move the SP2 driver to the CI section [media] ddbridge: use common DVB I2C client handling helpers [media] ngene: use common DVB I2C client handling helpers drivers/media/dvb-frontends/Kconfig| 18 +++-- drivers/media/pci/ddbridge/ddbridge-ci.c | 33 +-- drivers/media/pci/ddbridge/ddbridge-core.c | 37 ++--- drivers/media/pci/ngene/ngene-cards.c | 25 - drivers/media/pci/ngene/ngene-core.c | 43 +++--- 5 files changed, 40 insertions(+), 116 deletions(-) -- 2.16.1
[PATCH 1/4] [media] dvb-frontends/cxd2099: Kconfig additions
From: Daniel Scheller The cxd2099 driver makes use of the Regmap I2C kernel API, thus add "select REGMAP_I2C" to it's Kconfig block. Also, make it default "m" if !MEDIA_SUBDRV_AUTOSELECT, just like every other dvb-frontend driver. And, while at it, remove the hyphens around the help tag. Cc: Jasmin Jessich Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/Kconfig | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 2ad81907c714..fcfa1135557e 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -912,7 +912,9 @@ comment "Common Interface (EN50221) controller drivers" config DVB_CXD2099 tristate "CXD2099AR Common Interface driver" depends on DVB_CORE && I2C - ---help--- + select REGMAP_I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help A driver for the CI controller currently found mostly on Digital Devices DuoFlex CI (single) addon modules. -- 2.16.1
[PATCH 2/4] [media] dvb-frontends/Kconfig: move the SP2 driver to the CI section
From: Daniel Scheller The CIMaX SP2 driver is a EN50221 CI controller I2C driver similar to the cxd2099 driver. Move it's Kconfig block into the newly introduced CI subsection. Cc: Olli Salonen Cc: Antti Palosaari Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/Kconfig | 14 +++--- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index fcfa1135557e..687086cdb870 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -824,13 +824,6 @@ config DVB_A8293 depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT -config DVB_SP2 - tristate "CIMaX SP2" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - CIMaX SP2/SP2HF Common Interface module. - config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C @@ -920,6 +913,13 @@ config DVB_CXD2099 Say Y when you want to support these devices. +config DVB_SP2 + tristate "CIMaX SP2" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + CIMaX SP2/SP2HF Common Interface module. + comment "Tools to develop new frontends" config DVB_DUMMY_FE -- 2.16.1
[PATCH 4/4] [media] ngene: use common DVB I2C client handling helpers
From: Daniel Scheller Like in ddbridge, get rid of all duplicated I2C client handling constructs and rather make use of the newly added dvb_module_*() helpers. Makes things more clean and removes the (cosmetic) need for some variables. The check on a valid ptr on ci->en isn't really needed since the cxd2099 driver will set it at a time where it is going to return successfully from probing. Signed-off-by: Daniel Scheller --- drivers/media/pci/ngene/ngene-cards.c | 25 drivers/media/pci/ngene/ngene-core.c | 43 --- 2 files changed, 15 insertions(+), 53 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 37e9f0eb6d20..3ae7da2e9858 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -253,15 +253,7 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (chan->number & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (chan->number & 1) ? 0x63 : 0x60; /* * due to a hardware quirk with the I2C gate on the stv0367+tda18212 @@ -269,20 +261,13 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) * cold started, or it very likely will fail. */ if (dmdtype == DEMOD_TYPE_STV0367) - tuner_tda18212_ping(chan, i2c, board_info.addr); - - request_module(board_info.type); + tuner_tda18212_ping(chan, i2c, addr); - /* perform tuner init/attach */ - client = i2c_new_device(i2c, &board_info); - if (!client || !client->dev.driver) + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", "tda18212", i2c, addr, &config); + if (!client) goto err; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - goto err; - } - chan->i2c_client[0] = client; chan->i2c_client_fe = 1; diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index f69a8fc1ec2a..bef3c9fd75ce 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1408,7 +1408,6 @@ static void release_channel(struct ngene_channel *chan) { struct dvb_demux *dvbdemux = &chan->demux; struct ngene *dev = chan->dev; - struct i2c_client *client; if (chan->running) set_transfer(chan, 0); @@ -1427,12 +1426,9 @@ static void release_channel(struct ngene_channel *chan) dvb_unregister_frontend(chan->fe); /* release I2C client (tuner) if needed */ - client = chan->i2c_client[0]; - if (chan->i2c_client_fe && client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); + if (chan->i2c_client_fe) { + dvb_module_release(chan->i2c_client[0]); chan->i2c_client[0] = NULL; - client = NULL; } dvb_frontend_detach(chan->fe); @@ -1584,11 +1580,6 @@ static void cxd_attach(struct ngene *dev) struct ngene_ci *ci = &dev->ci; struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; - struct i2c_board_info board_info = { - .type = "cxd2099", - .addr = 0x40, - .platform_data = &cxd_cfg, - }; int ret; u8 type; @@ -1605,26 +1596,17 @@ static void cxd_attach(struct ngene *dev) } cxd_cfg.en = &ci->en; - - request_module(board_info.type); - - client = i2c_new_device(&dev->channel[0].i2c_adapter, &board_info); - if (!client || !client->dev.driver) - goto err_ret; - - if (!try_module_get(client->dev.driver->owner)) - goto err_i2c; - - if (!ci->en) - goto err_i2c; + client = dvb_module_probe("cxd2099", "cxd2099", + &dev->channel[0].i2c_adapter, + 0x40, &cxd_cfg); + if (!client) + goto err; ci->dev = dev; dev->channel[0].i2c_client[0] = client; return; -err_i2c: - i2c_unregister_device(client); -err_ret: +err: dev_err(pdev, "CXD2099AR attach failed\n"); return; } @
[PATCH v2 1/2] [media] ddbridge: use common DVB I2C client handling helpers
From: Daniel Scheller Instead of keeping duplicated I2C client handling construct, make use of the newly introduced dvb_module_*() helpers. This not only keeps things way cleaner and removes the need for duplicated I2C client attach code, but even allows to get rid of some variables that won't help in making things look cleaner anymore. The check on a valid ptr on port->en isn't really needed since the cxd2099 driver will set it at a time where it is going to return successfully from probing. Signed-off-by: Daniel Scheller --- V2: * pass NULL as (optional) I2C name when calling dvb_module_probe() drivers/media/pci/ddbridge/ddbridge-ci.c | 33 ++- drivers/media/pci/ddbridge/ddbridge-core.c | 36 ++ 2 files changed, 14 insertions(+), 55 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c index 6585ef54ac22..a9dbc4ebf94f 100644 --- a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -324,34 +324,20 @@ static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) { struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; - struct i2c_board_info board_info = { - .type = "cxd2099", - .addr = 0x40, - .platform_data = &cxd_cfg, - }; cxd_cfg.bitrate = bitrate; cxd_cfg.en = &port->en; - request_module(board_info.type); - - client = i2c_new_device(&port->i2c->adap, &board_info); - if (!client || !client->dev.driver) - goto err_ret; - - if (!try_module_get(client->dev.driver->owner)) - goto err_i2c; - - if (!port->en) - goto err_i2c; + client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap, + 0x40, &cxd_cfg); + if (!client) + goto err; port->dvb[0].i2c_client[0] = client; port->en_freedata = 0; return 0; -err_i2c: - i2c_unregister_device(client); -err_ret: +err: dev_err(port->dev->dev, "CXD2099AR attach failed\n"); return -ENODEV; } @@ -385,18 +371,13 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) void ddb_ci_detach(struct ddb_port *port) { - struct i2c_client *client; - if (port->dvb[0].dev) dvb_unregister_device(port->dvb[0].dev); if (port->en) { dvb_ca_en50221_release(port->en); - client = port->dvb[0].i2c_client[0]; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } + dvb_module_release(port->dvb[0].i2c_client[0]); + port->dvb[0].i2c_client[0] = NULL; /* free alloc'ed memory if needed */ if (port->en_freedata) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index f9bee36f1cad..90687eff5909 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -999,37 +999,21 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (input->nr & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (input->nr & 1) ? 0x63 : 0x60; /* due to a hardware quirk with the I2C gate on the stv0367+tda18212 * combo, the tda18212 must be probed by reading it's id _twice_ when * cold started, or it very likely will fail. */ if (porttype == DDB_TUNER_DVBCT_ST) - tuner_tda18212_ping(input, board_info.addr); - - request_module(board_info.type); - - /* perform tuner init/attach */ - client = i2c_new_device(adapter, &board_info); - if (!client || !client->dev.driver) - goto err; + tuner_tda18212_ping(input, addr); - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", NULL, adapter, addr, &config); + if (!client) goto err; - } dvb->i2c_client[0] = client; - return 0; err: dev_err(dev, "TDA18212 tuner not found. Device is not fully operational.\n"); @@ -1253,7 +1237,6 @@ static void dvb_input_detach(struct ddb_input *input) {
[PATCH v2 2/2] [media] ngene: use common DVB I2C client handling helpers
From: Daniel Scheller Like in ddbridge, get rid of all duplicated I2C client handling constructs and rather make use of the newly added dvb_module_*() helpers. Makes things more clean and removes the (cosmetic) need for some variables. The check on a valid ptr on ci->en isn't really needed since the cxd2099 driver will set it at a time where it is going to return successfully from probing. Signed-off-by: Daniel Scheller --- V2: * pass NULL as (optional) I2C name when calling dvb_module_probe() drivers/media/pci/ngene/ngene-cards.c | 25 drivers/media/pci/ngene/ngene-core.c | 43 --- 2 files changed, 15 insertions(+), 53 deletions(-) diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 37e9f0eb6d20..65fc8f23ad86 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -253,15 +253,7 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) .if_dvbt2_8 = 4000, .if_dvbc = 5000, }; - struct i2c_board_info board_info = { - .type = "tda18212", - .platform_data = &config, - }; - - if (chan->number & 1) - board_info.addr = 0x63; - else - board_info.addr = 0x60; + u8 addr = (chan->number & 1) ? 0x63 : 0x60; /* * due to a hardware quirk with the I2C gate on the stv0367+tda18212 @@ -269,20 +261,13 @@ static int tuner_attach_tda18212(struct ngene_channel *chan, u32 dmdtype) * cold started, or it very likely will fail. */ if (dmdtype == DEMOD_TYPE_STV0367) - tuner_tda18212_ping(chan, i2c, board_info.addr); - - request_module(board_info.type); + tuner_tda18212_ping(chan, i2c, addr); - /* perform tuner init/attach */ - client = i2c_new_device(i2c, &board_info); - if (!client || !client->dev.driver) + /* perform tuner probe/init/attach */ + client = dvb_module_probe("tda18212", NULL, i2c, addr, &config); + if (!client) goto err; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - goto err; - } - chan->i2c_client[0] = client; chan->i2c_client_fe = 1; diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index f69a8fc1ec2a..3b9a1bfaf6c0 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -1408,7 +1408,6 @@ static void release_channel(struct ngene_channel *chan) { struct dvb_demux *dvbdemux = &chan->demux; struct ngene *dev = chan->dev; - struct i2c_client *client; if (chan->running) set_transfer(chan, 0); @@ -1427,12 +1426,9 @@ static void release_channel(struct ngene_channel *chan) dvb_unregister_frontend(chan->fe); /* release I2C client (tuner) if needed */ - client = chan->i2c_client[0]; - if (chan->i2c_client_fe && client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); + if (chan->i2c_client_fe) { + dvb_module_release(chan->i2c_client[0]); chan->i2c_client[0] = NULL; - client = NULL; } dvb_frontend_detach(chan->fe); @@ -1584,11 +1580,6 @@ static void cxd_attach(struct ngene *dev) struct ngene_ci *ci = &dev->ci; struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; struct i2c_client *client; - struct i2c_board_info board_info = { - .type = "cxd2099", - .addr = 0x40, - .platform_data = &cxd_cfg, - }; int ret; u8 type; @@ -1605,26 +1596,17 @@ static void cxd_attach(struct ngene *dev) } cxd_cfg.en = &ci->en; - - request_module(board_info.type); - - client = i2c_new_device(&dev->channel[0].i2c_adapter, &board_info); - if (!client || !client->dev.driver) - goto err_ret; - - if (!try_module_get(client->dev.driver->owner)) - goto err_i2c; - - if (!ci->en) - goto err_i2c; + client = dvb_module_probe("cxd2099", NULL, + &dev->channel[0].i2c_adapter, + 0x40, &cxd_cfg); + if (!client) + goto err; ci->dev = dev; dev->channel[0].i2c_client[0] = client; return; -err_i2c: - i2c_unregister_device(client); -err_ret: +err: dev_err(pdev, "CXD2099AR atta
Re: [PATCH 3/4] [media] ddbridge: use common DVB I2C client handling helpers
Am Wed, 7 Mar 2018 16:44:49 -0300 schrieb Mauro Carvalho Chehab : > Em Wed, 7 Mar 2018 20:23:49 +0100 > Daniel Scheller escreveu: > > > From: Daniel Scheller > > > > Instead of keeping duplicated I2C client handling construct, make > > use of the newly introduced dvb_module_*() helpers. This not only > > keeps things way cleaner and removes the need for duplicated I2C > > client attach code, but even allows to get rid of some variables > > that won't help in making things look cleaner anymore. > > > > The check on a valid ptr on port->en isn't really needed since the > > cxd2099 driver will set it at a time where it is going to return > > successfully from probing. > > > > Signed-off-by: Daniel Scheller > > --- > > drivers/media/pci/ddbridge/ddbridge-ci.c | 33 > > ++ > > drivers/media/pci/ddbridge/ddbridge-core.c | 37 > > +++--- 2 files changed, 15 insertions(+), > > 55 deletions(-) > > > > diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c > > b/drivers/media/pci/ddbridge/ddbridge-ci.c index > > 6585ef54ac22..d0ce6a1f1bd0 100644 --- > > a/drivers/media/pci/ddbridge/ddbridge-ci.c +++ > > b/drivers/media/pci/ddbridge/ddbridge-ci.c @@ -324,34 +324,20 @@ > > static int ci_cxd2099_attach(struct ddb_port *port, u32 bitrate) { > > struct cxd2099_cfg cxd_cfg = cxd_cfgtmpl; > > struct i2c_client *client; > > - struct i2c_board_info board_info = { > > - .type = "cxd2099", > > - .addr = 0x40, > > - .platform_data = &cxd_cfg, > > - }; > > > > cxd_cfg.bitrate = bitrate; > > cxd_cfg.en = &port->en; > > > > - request_module(board_info.type); > > - > > - client = i2c_new_device(&port->i2c->adap, &board_info); > > - if (!client || !client->dev.driver) > > - goto err_ret; > > - > > - if (!try_module_get(client->dev.driver->owner)) > > - goto err_i2c; > > - > > - if (!port->en) > > - goto err_i2c; > > + client = dvb_module_probe("cxd2099", "cxd2099", > > &port->i2c->adap, > > + 0x40, &cxd_cfg); > > Here and on all similar calls, there's no need to duplicate the name, > if they're identical. Just use NULL at the second time, e. g.: > > client = dvb_module_probe("cxd2099", NULL, &port->i2c->adap, > 0x40, &cxd_cfg); > > The dvb_module_probe() will use the same string for both. Convinced (wanted to make this look "complete" and "proper"). V2 sent, skipped the cover letter though :-) Best regards, Daniel Scheller -- https://github.com/herrnst
[PATCH] [media] ttpci: improve printing of encoded MAC address
From: Daniel Scheller When loading the budget_av driver for ie. a KNC1 DVB-C TDA10024 card, which makes use of the ttpci eeprom check functionality (that always fails on these cards, but that's no issue at all), this is printed to the kernel log: [ 10.497333] saa7146 (0): dma buffer size 192512 [ 10.497335] dvbdev: DVB: registering new adapter (KNC1 DVB-C TDA10024) [ 10.545007] adapter failed MAC signature check [ 10.545009] encoded MAC from EEPROM was [ 10.545010] ff: [ 10.545011] ff: [ 10.545011] ff: ... [ 10.545021] ff [ 10.832422] budget_av: KNC1-4: MAC addr = 00:09:d6:6d:b3:be with the 'ff' being repeated for a total of 20 times. Improve that by using the %*phC format specifier instead dprintk()'ing every byte of the encoded MAC separately. This obsoletes the int i, and the kernel log looks cleaner: [ 3234.383153] saa7146 (0): dma buffer size 192512 [ 3234.383154] dvbdev: DVB: registering new adapter (KNC1 DVB-C TDA10024) [ 3234.428745] adapter failed MAC signature check [ 3234.428747] encoded MAC from EEPROM was ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff [ 3234.728194] budget_av: KNC1-0: MAC addr = 00:09:d6:6d:b3:be Signed-off-by: Daniel Scheller --- drivers/media/pci/ttpci/ttpci-eeprom.c | 9 +++-- 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c index 9534f29c1ffd..78c7a6589be5 100644 --- a/drivers/media/pci/ttpci/ttpci-eeprom.c +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -138,7 +138,7 @@ static int ttpci_eeprom_read_encodedMAC(struct i2c_adapter *adapter, u8 * encode int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) { - int ret, i; + int ret; u8 encodedMAC[20]; u8 decodedMAC[6]; @@ -153,11 +153,8 @@ int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) ret = getmac_tt(decodedMAC, encodedMAC); if( ret != 0 ) { dprintk("adapter failed MAC signature check\n"); - dprintk("encoded MAC from EEPROM was " ); - for(i=0; i<19; i++) { - dprintk( "%.2x:", encodedMAC[i]); - } - dprintk("%.2x\n", encodedMAC[19]); + dprintk("encoded MAC from EEPROM was %*phC", + (int)sizeof(encodedMAC), &encodedMAC); eth_zero_addr(proposed_mac); return ret; } -- 2.16.1
Re: [PATCH v3 00/13] stv0367/ddbridge: support CTv6/FlexCT hardware
Am Wed, 12 Apr 2017 21:23:27 +0200 schrieb Daniel Scheller : > Am Wed, 29 Mar 2017 18:43:00 +0200 > schrieb Daniel Scheller : > > > From: Daniel Scheller > > > > Third iteration of the DD CineCTv6/FlexCT support patches with > > mostly all things cleaned up that popped up so far. Obsoletes V1 > > and V2 series. > > > > These patches enhance the functionality of dvb-frontends/stv0367 to > > work with Digital Devices hardware driven by the ST STV0367 > > demodulator chip and adds probe & attach bits to ddbridge to make > > use of them, effectively enabling full support for CineCTv6 PCIe > > bridges and (older) DuoFlex CT addon modules. > > Since V1 was sent over five weeks ago: Ping? Anyone? I'd really like > to get this upstreamed. Don't want to sound impatient, but V1 nears nine weeks, so: Second Ping. From what I can see, the two affected drivers aren't (at least) actively maintained anymore, or maintainers may be MIA. So: Mauro, mind having a look if you've got some spare time? Thanks & best regards, Daniel
Re: Build fails Ubuntu 17.04 / "error: implicit declaration of function"
Am Sun, 28 May 2017 21:06:33 +0200 schrieb Karl Wallin : All, > In "/home/ubuntu/media_build/v4l/cec-core.c" changed row 142 from: > "ret = cdev_device_add(&devnode->cdev, &devnode->dev);" to: > "ret = device_add(&devnode->dev);" > and row 186 from: > "cdev_device_del(&devnode->cdev, &devnode->dev);" to: > "device_del(&devnode->dev);" Until the upstream media_build repository gets the neccessary backport patch treatment, you can apply [1] and [2] to media_build which should fix all build issues. Best regards, Daniel [1] https://github.com/herrnst/media_build/commit/4766a716c629707d58d625c6cdfd8c395fd6ed61 [2] https://github.com/herrnst/media_build/commit/01507a9c32a301c8fc021dcaf1b943799ff3da51
Re: [PATCH v3 00/13] stv0367/ddbridge: support CTv6/FlexCT hardware
Am Sun, 7 May 2017 17:42:12 +0200 schrieb Daniel Scheller : > Am Wed, 12 Apr 2017 21:23:27 +0200 > schrieb Daniel Scheller : > > > Am Wed, 29 Mar 2017 18:43:00 +0200 > > schrieb Daniel Scheller : > > > > > From: Daniel Scheller > > > > > > Third iteration of the DD CineCTv6/FlexCT support patches with > > > mostly all things cleaned up that popped up so far. Obsoletes V1 > > > and V2 series. > > > > > > These patches enhance the functionality of dvb-frontends/stv0367 > > > to work with Digital Devices hardware driven by the ST STV0367 > > > demodulator chip and adds probe & attach bits to ddbridge to make > > > use of them, effectively enabling full support for CineCTv6 PCIe > > > bridges and (older) DuoFlex CT addon modules. > > > > Since V1 was sent over five weeks ago: Ping? Anyone? I'd really like > > to get this upstreamed. > > Don't want to sound impatient, but V1 nears nine weeks, so: Second > Ping. Friendly third time Ping on this - Really, I'd like to have this merged so those quite aging (but still fine) DD CineCTv6 boards finally are supported without having to install out-of-tree drivers which even break the V4L-DVB subsystem... Thanks & regards, Daniel
Re: [PATCH 00/19] cxd2841er/ddbridge: support Sony CXD28xx hardware
Am Sun, 9 Apr 2017 21:38:09 +0200 schrieb Daniel Scheller : > Important note: This series depends on the stv0367/ddbridge series > posted earlier (patches 12 [1] and 13 [2], depending on the I2C > functions and the TDA18212 attach function). > > This series improves the cxd2841er demodulator driver and adds some > bits to make it more versatile to be used in more scenarios. Also, > the ddbridge code is updated to recognize all hardware (PCIe > cards/bridges and DuoFlex modules) with Sony CXD28xx tuners, > including the newly introduced MaxA8 eight-tuner C2T2 cards. > > The series has been tested (together with the STV0367 series) on a > wide variety of cards, including CineCTv7, DuoFlex C(2)T2 modules and > MaxA8 cards without any issues. Testing was done with TVHeadend, VDR > and MythTV. > > Note that the i2c_gate_ctrl() flag is needed in this series aswell > since the i2c_gate_ctrl function needs to be remapped and mutex_lock > protected for the same reasons as in the STV0367 series. > > Besides printk() warnings, checkpatch.pl doesn't complain. Ping on this series aswell. Abylay, would you please mind taking a look at the cxd2841er changes and check if you're fine with them? Regards, Daniel
Re: [PATCH 00/19] cxd2841er/ddbridge: support Sony CXD28xx hardware
Am Wed, 31 May 2017 08:30:34 -0400 schrieb Abylay Ospan : Hi Abylay, > I have ack'ed all patches related to cxd2841er. Please check am i > missing something ? Thank you very much for your review and your ACKs, and in general taking time to look into them! You didn't miss any of the patches :) Will add your ACKs to the cxd2841er patches in a very likely upcoming V2 of the series. > I see some good flags (CXD2841ER_NO_WAIT_LOCK and > CXD2841ER_EARLY_TUNE). I should check it for our boards too :) Re EARLY_TUNE - I wasn't sure if the order of tuner/demod setup is of importance on your devices. When picking the IF freq from the tuner though, we first need to tune and then set up the demod since the demod queries the tuner about this. If your hardware also works with the "earlier tune", maybe we should drop this flag/condition and just move the tune call up. Re NO_WAIT_LOCK - works fine with or without this. However, when e.g. using TVH and looking at the stats, the Web UI will freeze if a retune occurs. Again, not sure if it's absolutely required on your hardware/software - if not, I suggest to remove the flag together with the wait lock entirely. Looking forward for your results and opinions! :-) Best regards, Daniel Scheller
Re: [PATCH v3 00/13] stv0367/ddbridge: support CTv6/FlexCT hardware
Am Sun, 28 May 2017 23:45:37 +0200 schrieb Daniel Scheller : > Am Sun, 7 May 2017 17:42:12 +0200 > schrieb Daniel Scheller : > > > Am Wed, 12 Apr 2017 21:23:27 +0200 > > schrieb Daniel Scheller : > > > > > Am Wed, 29 Mar 2017 18:43:00 +0200 > > > schrieb Daniel Scheller : > > > > > > > From: Daniel Scheller > > > > > > > > Third iteration of the DD CineCTv6/FlexCT support patches with > > > > mostly all things cleaned up that popped up so far. Obsoletes V1 > > > > and V2 series. > > > > > > > > These patches enhance the functionality of dvb-frontends/stv0367 > > > > to work with Digital Devices hardware driven by the ST STV0367 > > > > demodulator chip and adds probe & attach bits to ddbridge to > > > > make use of them, effectively enabling full support for > > > > CineCTv6 PCIe bridges and (older) DuoFlex CT addon > > > > modules. > > > > > > Since V1 was sent over five weeks ago: Ping? Anyone? I'd really > > > like to get this upstreamed. > > > > Don't want to sound impatient, but V1 nears nine weeks, so: Second > > Ping. > > Friendly third time Ping on this - Really, I'd like to have this > merged so those quite aging (but still fine) DD CineCTv6 boards > finally are supported without having to install out-of-tree drivers > which even break the V4L-DVB subsystem... Well. From how things look, these and the cxd2841er+C2T2 ddbridge support patches won't make it in time for the 4.13 merge window. Also, unfortunately, the original owners and/or maintainers of the affected drivers (besides cxd2841er), namely stv0367 and ddbridge, either are MIA or not interested in reviewing or acking this. I have plenty of more work (patches) done, all building upon this CT and C2T2 hardware support, which - together with the work Jasmin has done regarding the en50221 and cxd2099 support - would finally bring the in-tree ddbridge driver on par with the package Digital Devices' provides, having addressed most of the critics the previous attempts to bump the driver received (incremental changes which are more or less easy to review, from what can be done by tearing tarballs without proper changelogs apart). The original series of this will be four(!) months old soon :/ Is there anything wrong with this? How to proceed with this? (Cc Hans since you also seem to be reviewing patches) That said, fourth ping. Best regards, Daniel Scheller
[PATCH] [media] ddbridge: use pr_* macros in favor of printk
From: Daniel Scheller Side effect: KERN_DEBUG messages aren't written to the kernel log anymore. This also improves the tda18212_ping reporting a bit so users know that if pinging wasn't successful, bad things might happen. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-core.c | 64 +++--- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9420479bee9a..fff03a332e08 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -17,6 +17,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -124,10 +126,10 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); if (stat == 0) { - printk(KERN_ERR "I2C timeout\n"); + pr_err("I2C timeout\n"); { /* MSI debugging*/ u32 istat = ddbreadl(INTERRUPT_STATUS); - printk(KERN_ERR "IRS %08x\n", istat); + pr_err("IRS %08x\n", istat); ddbwritel(istat, INTERRUPT_ACK); } return -EIO; @@ -533,7 +535,7 @@ static u32 ddb_input_avail(struct ddb_input *input) off = (stat & 0x7ff) << 7; if (ctrl & 4) { - printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); + pr_err("IA %d %d %08x\n", idx, off, ctrl); ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); return 0; } @@ -619,7 +621,7 @@ static int demod_attach_drxk(struct ddb_input *input) fe = input->fe = dvb_attach(drxk_attach, &config, i2c); if (!input->fe) { - printk(KERN_ERR "No DRXK found!\n"); + pr_err("No DRXK found!\n"); return -ENODEV; } fe->sec_priv = input; @@ -637,7 +639,7 @@ static int tuner_attach_tda18271(struct ddb_input *input) input->fe->ops.i2c_gate_ctrl(input->fe, 1); fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); + pr_err("No TDA18271 found!\n"); return -ENODEV; } if (input->fe->ops.i2c_gate_ctrl) @@ -676,7 +678,7 @@ static int demod_attach_stv0367(struct ddb_input *input) &ddb_stv0367_config[(input->nr & 1)], i2c); if (!input->fe) { - printk(KERN_ERR "stv0367ddb_attach failed (not found?)\n"); + pr_err("stv0367ddb_attach failed (not found?)\n"); return -ENODEV; } @@ -693,14 +695,14 @@ static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr) u8 tda_id[2]; u8 subaddr = 0x00; - printk(KERN_DEBUG "stv0367-tda18212 tuner ping\n"); + pr_debug("stv0367-tda18212 tuner ping\n"); if (input->fe->ops.i2c_gate_ctrl) input->fe->ops.i2c_gate_ctrl(input->fe, 1); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) - printk(KERN_DEBUG "tda18212 ping 1 fail\n"); + pr_debug("tda18212 ping 1 fail\n"); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) - printk(KERN_DEBUG "tda18212 ping 2 fail\n"); + pr_warn("tda18212 ping failed, expect problems\n"); if (input->fe->ops.i2c_gate_ctrl) input->fe->ops.i2c_gate_ctrl(input->fe, 0); @@ -728,7 +730,7 @@ static int demod_attach_cxd28xx(struct ddb_input *input, int par, int osc24) input->fe = dvb_attach(cxd2841er_attach_t_c, &cfg, i2c); if (!input->fe) { - printk(KERN_ERR "No Sony CXD28xx found!\n"); + pr_err("No Sony CXD28xx found!\n"); return -ENODEV; } @@ -786,7 +788,7 @@ static int tuner_attach_tda18212(struct ddb_input *input, u32 porttype) return 0; err: - printk(KERN_INFO "TDA18212 tuner not found. Device is not fully operational.\n"); + pr_warn("TDA18212 tuner not found. Device is not fully operational.\n"); return -ENODEV; } @@ -853,13 +855,13 @@ static int demod_attach_stv0900(struct ddb_input *input, int type) (input->nr & 1) ? STV090x_DEMODULATOR_1
[PATCH 2/4] [media] dvb-frontends/stv0367: split SNR determination into functions
From: Daniel Scheller The read_snr() functions currently do some magic to return relative scale values when called. Split out register readouts into separate functions so the functionality can be reused in some other way. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 68 +-- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 5374d4eaabd6..bb498f942ebd 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -1437,7 +1437,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, return 0; } -static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) +static u32 stv0367ter_snr_readreg(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; u32 snru32 = 0; @@ -1453,10 +1453,16 @@ static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) cpt++; } - snru32 /= 10;/*average on 10 values*/ - *snr = snru32 / 1000; + return snru32; +} + +static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + u32 snrval = stv0367ter_snr_readreg(fe); + + *snr = snrval / 1000; return 0; } @@ -2702,51 +2708,61 @@ static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength) return 0; } -static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) +static int stv0367cab_snr_power(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; - u32 noisepercentage; enum stv0367cab_mod QAMSize; - u32 regval = 0, temp = 0; - int power, i; QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); switch (QAMSize) { case FE_CAB_MOD_QAM4: - power = 21904; - break; + return 21904; case FE_CAB_MOD_QAM16: - power = 20480; - break; + return 20480; case FE_CAB_MOD_QAM32: - power = 23040; - break; + return 23040; case FE_CAB_MOD_QAM64: - power = 21504; - break; + return 21504; case FE_CAB_MOD_QAM128: - power = 23616; - break; + return 23616; case FE_CAB_MOD_QAM256: - power = 21760; - break; - case FE_CAB_MOD_QAM512: - power = 1; - break; + return 21760; case FE_CAB_MOD_QAM1024: - power = 21280; - break; + return 21280; default: - power = 1; break; } + return 1; +} + +static int stv0367cab_snr_readreg(struct dvb_frontend *fe, int avgdiv) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 regval = 0; + int i; + for (i = 0; i < 10; i++) { regval += (stv0367_readbits(state, F367CAB_SNR_LO) + 256 * stv0367_readbits(state, F367CAB_SNR_HI)); } - regval /= 10; /*for average over 10 times in for loop above*/ + if (avgdiv) + regval /= 10; + + return regval; +} + +static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 noisepercentage; + u32 regval = 0, temp = 0; + int power; + + power = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 1); + if (regval != 0) { temp = power * (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER))); -- 2.13.0
[PATCH 3/4] [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T
From: Daniel Scheller Add signal-to-noise-ratio as provided by the demodulator in decibel scale. QAM/DVB-C needs some intlog calculation to have usable dB values, OFDM/ DVB-T values from the demod look alright already and are provided as-is. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 33 + 1 file changed, 33 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index bb498f942ebd..0b13a407df23 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -25,6 +25,8 @@ #include #include +#include "dvb_math.h" + #include "stv0367.h" #include "stv0367_defs.h" #include "stv0367_regs.h" @@ -33,6 +35,9 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 +/* snr logarithmic calc */ +#define INTLOG10X100(x) ((u32) (((u64) intlog10(x) * 100) >> 24)) + static int stvdebug; module_param_named(debug, stvdebug, int, 0644); @@ -3013,6 +3018,33 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_snr(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int cab_pwr; + u32 regval, tmpval, snrval = 0; + + switch (state->activedemod) { + case demod_ter: + snrval = stv0367ter_snr_readreg(fe); + break; + case demod_cab: + cab_pwr = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 0); + + tmpval = (cab_pwr * 320) / regval; + snrval = ((tmpval != 0) ? INTLOG10X100(tmpval) : 0) * 100; + break; + default: + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + p->cnr.stat[0].uvalue = snrval; +} + static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; @@ -3069,6 +3101,7 @@ static int stv0367ddb_get_frontend(struct dvb_frontend *fe, } stv0367ddb_read_ucblocks(fe); + stv0367ddb_read_snr(fe); return 0; } -- 2.13.0
[PATCH 4/4] [media] dvb-frontends/stv0367: DVB-C signal strength statistics
From: Daniel Scheller Provide QAM/DVB-C signal strength in decibel scale. Values returned from stv0367cab_get_rf_lvl() are good but need to be multiplied as they're in 1dBm precision. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 20 1 file changed, 20 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 0b13a407df23..cf684ba70a3f 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -3018,6 +3018,25 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_signal_strength(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + s32 signalstrength; + + switch (state->activedemod) { + case demod_cab: + signalstrength = stv0367cab_get_rf_lvl(state) * 1000; + break; + default: + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->strength.stat[0].scale = FE_SCALE_DECIBEL; + p->strength.stat[0].uvalue = signalstrength; +} + static void stv0367ddb_read_snr(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; @@ -3102,6 +3121,7 @@ static int stv0367ddb_get_frontend(struct dvb_frontend *fe, stv0367ddb_read_ucblocks(fe); stv0367ddb_read_snr(fe); + stv0367ddb_read_signal_strength(fe); return 0; } -- 2.13.0
[PATCH 0/4] STV0367/DDB DVBv5 signal statistics
From: Daniel Scheller This series adds DVBv5 statistics support to the new DDB codepath of the stv0367 demodulator driver. The changes utilise already existing functionality (in form of register readouts), but wraps the reads in separate functions so the existing relative scale reporting can be kept as-is, while adding the v5 stats in dB scale where appropriate. >From my own testing: Reported values look approx. the same as those reported by the cxd2841er driver for both -C and -T. Daniel Scheller (4): [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks [media] dvb-frontends/stv0367: split SNR determination into functions [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T [media] dvb-frontends/stv0367: DVB-C signal strength statistics drivers/media/dvb-frontends/stv0367.c | 180 -- 1 file changed, 150 insertions(+), 30 deletions(-) -- 2.13.0
[PATCH 1/4] [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks
From: Daniel Scheller This adds the basics to stv0367ddb_get_frontend() to be able to properly provide signal statistics in DVBv5 format. Also adds UCB readout and provides those values. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 59 --- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index e726c2e00460..5374d4eaabd6 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2997,21 +2997,64 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, return -EINVAL; } +static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 ucblocks = 0; + + switch (state->activedemod) { + case demod_ter: + stv0367ter_read_ucblocks(fe, &ucblocks); + break; + case demod_cab: + stv0367cab_read_ucblcks(fe, &ucblocks); + break; + default: + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->block_error.stat[0].scale = FE_SCALE_COUNTER; + p->block_error.stat[0].uvalue = ucblocks; +} + static int stv0367ddb_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p) { struct stv0367_state *state = fe->demodulator_priv; + int ret = -EINVAL; + enum fe_status status = 0; switch (state->activedemod) { case demod_ter: - return stv0367ter_get_frontend(fe, p); + ret = stv0367ter_get_frontend(fe, p); + break; case demod_cab: - return stv0367cab_get_frontend(fe, p); - default: + ret = stv0367cab_get_frontend(fe, p); break; + default: + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; } - return -EINVAL; + /* read fe lock status */ + if (!ret) + ret = stv0367ddb_read_status(fe, &status); + + /* stop if get_frontend failed or if demod isn't locked */ + if (ret || !(status & FE_HAS_LOCK)) { + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; + } + + stv0367ddb_read_ucblocks(fe); + + return 0; } static int stv0367ddb_sleep(struct dvb_frontend *fe) @@ -3035,6 +3078,7 @@ static int stv0367ddb_sleep(struct dvb_frontend *fe) static int stv0367ddb_init(struct stv0367_state *state) { struct stv0367ter_state *ter_state = state->ter_state; + struct dtv_frontend_properties *p = &state->fe.dtv_property_cache; stv0367_writereg(state, R367TER_TOPCTRL, 0x10); @@ -3109,6 +3153,13 @@ static int stv0367ddb_init(struct stv0367_state *state) ter_state->first_lock = 0; ter_state->unlock_counter = 2; + p->strength.len = 1; + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.len = 1; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.len = 1; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; } -- 2.13.0
DD support improvements (was: Re: [PATCH v3 00/13] stv0367/ddbridge: support CTv6/FlexCT hardware)
Am Tue, 20 Jun 2017 09:36:45 -0300 schrieb Mauro Carvalho Chehab : Hi Mauro, > Em Mon, 19 Jun 2017 22:18:21 +0200 > Daniel Scheller escreveu: > > > Well. From how things look, these and the cxd2841er+C2T2 ddbridge > > support patches won't make it in time for the 4.13 merge window. > > There is time. I just merged this series today. Oh. Well, this, together with the other series, came as a (quite positive) surprise this morning - thank you very very much! > The thing is that we currently have few developers working on > DVB, and no sub-maintainers. Due to that, I need to review > them myself, with I usually do after reviewing/applying patches > from sub-maintainers. Understood. Though, and please don't get me wrong - Tearing apart and under how things in the driver, the vendor driver package, the media and DVB subsystem aswell as kernel parts, additionally aligning the patches/commits with all remarks from previous submissions in mind took quite some spare time for more than a year now, getting no responses at all honestly started to get frustrating. > > Also, unfortunately, the original owners and/or maintainers of the > > affected drivers (besides cxd2841er), namely stv0367 and ddbridge, > > either are MIA or not interested in reviewing or acking this. > > Yeah, it would be great if Ralph would have some time to review > them, or to submit a new series adding all pending features from > DD drivers upstream. This would of course be the way to go. OTOH, the in-kernel driver already diverged quite a lot to that what DD publishes and maintains, and lots of people agree this situation must be improved. > > I have plenty of more work (patches) done, all building upon this CT > > and C2T2 hardware support, which - together with the work Jasmin has > > done regarding the en50221 and cxd2099 support - would finally bring > > the in-tree ddbridge driver on par with the package Digital Devices' > > provides, having addressed most of the critics the previous > > attempts to bump the driver received (incremental changes which are > > more or less easy to review, from what can be done by tearing > > tarballs without proper changelogs apart). > > Both Jasmin and Thomas could have reviewed it, and replied > if they tested it, and on what conditions. I tend to give > people some time to review/test patches, before doing my > review, as I don't usually have time for testing everything > myself. Not sure about Thomas, but I know that Jasmin doesn't own and/ore uses such cards. However, for upcoming patches, I'll try to drag people to the list for some comments, thanks for the pointer. Speaking of patches and pending features (and generally syncing drivers), this is what I plan to send to the list (in order, mostly depending on each other): - Maybe for 4.14: Support for the CineS2 V7 and FlexV4 line of cards/modules. This mainly involves a new demod driver (stv0910) and a new tuner driver (stv6111). Permissions for this are cleared with Ralph already. The glue code needed in ddbridge is rather easy, and as some ground work (mostly the MachXO2 support from the 2841 series) is now in, the changes are quite small. Patches are ready so far but need more cleanup (checkpatch fixes, camel case and such things). - The "big" ddbridge update. I'm thinking of two ways to do this: * Do this in one commit, being a huge code bump, bringing ddbridge to version 0.9.28 (as per vendor versioning). This is mostly ready and successful in use by many testers and in my Gentoo ddbridge kernel sources overlay. Should get some more cleanups though (still some GTL link bits left which are not needed), and all fixes which went to the in-kernel driver like __user annotations need to be put back in. Big drawback: A mess to review. * Try to tear apart most if not all upstream vendor driver tar archives and recreate individual patches out of this. For reference, we need to go from what is in the kernel which is something inbetween v0.5 and v0.8 up to and including version 0.9.29. I'm currently working on this from time to time, and I can assure you that this is an extremely tedious and unthankful thing to do (currently nearly done with 0.9.9b, approx. 20 releases left). This might be better to review, but this will also result in something like 100-200 commits, without guarantee of having everything correct. Reviewers will hate me for this, but I'd personally prefer the first option (less work, verified working on quite some installs, less clutter in GIT, but the drawback of reviewability). - Last bit: DD MaxS4/S8 support. Requires another new demod driver (mxl5xx) and some more bits (not only glue code, but also some operation mode control and LNB handl
[PATCH] [media] dvb-frontends/lnbh25: improve kernellog output
From: Daniel Scheller Use dev_dbg() in conjunction with the %*ph format macro to print the vmon status debug, thus hiding continuous hexdumping from default log levels. Also, change the attach success log line from error to info severity. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/lnbh25.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/media/dvb-frontends/lnbh25.c b/drivers/media/dvb-frontends/lnbh25.c index ef3021e964be..cb486e879fdd 100644 --- a/drivers/media/dvb-frontends/lnbh25.c +++ b/drivers/media/dvb-frontends/lnbh25.c @@ -76,8 +76,8 @@ static int lnbh25_read_vmon(struct lnbh25_priv *priv) return ret; } } - print_hex_dump_bytes("lnbh25_read_vmon: ", - DUMP_PREFIX_OFFSET, status, sizeof(status)); + dev_dbg(&priv->i2c->dev, "%s(): %*ph\n", + __func__, (int) sizeof(status), status); if ((status[0] & (LNBH25_STATUS_OFL | LNBH25_STATUS_VMON)) != 0) { dev_err(&priv->i2c->dev, "%s(): voltage in failure state, status reg 0x%x\n", @@ -178,7 +178,7 @@ struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe, fe->ops.release_sec = lnbh25_release; fe->ops.set_voltage = lnbh25_set_voltage; - dev_err(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n", + dev_info(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n", __func__, priv->i2c_address); return fe; } -- 2.13.0
Re: [PATCH 1/4] [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks
Am Wed, 21 Jun 2017 09:06:22 +0300 schrieb Antti Palosaari : > On 06/20/2017 08:45 PM, Daniel Scheller wrote: > > From: Daniel Scheller > > > > This adds the basics to stv0367ddb_get_frontend() to be able to properly > > provide signal statistics in DVBv5 format. Also adds UCB readout and > > provides those values. > > > > Signed-off-by: Daniel Scheller > > --- > > drivers/media/dvb-frontends/stv0367.c | 59 > > --- > > 1 file changed, 55 insertions(+), 4 deletions(-) > > > > diff --git a/drivers/media/dvb-frontends/stv0367.c > > b/drivers/media/dvb-frontends/stv0367.c > > index e726c2e00460..5374d4eaabd6 100644 > > --- a/drivers/media/dvb-frontends/stv0367.c > > +++ b/drivers/media/dvb-frontends/stv0367.c > > @@ -2997,21 +2997,64 @@ static int stv0367ddb_read_status(struct > > dvb_frontend *fe, > > return -EINVAL; > > } > > > > +static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) > > +{ > > + struct stv0367_state *state = fe->demodulator_priv; > > + struct dtv_frontend_properties *p = &fe->dtv_property_cache; > > + u32 ucblocks = 0; > > + > > + switch (state->activedemod) { > > + case demod_ter: > > + stv0367ter_read_ucblocks(fe, &ucblocks); > > + break; > > + case demod_cab: > > + stv0367cab_read_ucblcks(fe, &ucblocks); > > + break; > > + default: > > + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + return; > > + } > > + > > + p->block_error.stat[0].scale = FE_SCALE_COUNTER; > > + p->block_error.stat[0].uvalue = ucblocks; > > +} > > + > > static int stv0367ddb_get_frontend(struct dvb_frontend *fe, > >struct dtv_frontend_properties *p) > > { > > struct stv0367_state *state = fe->demodulator_priv; > > + int ret = -EINVAL; > > + enum fe_status status = 0; > > > > switch (state->activedemod) { > > case demod_ter: > > - return stv0367ter_get_frontend(fe, p); > > + ret = stv0367ter_get_frontend(fe, p); > > + break; > > case demod_cab: > > - return stv0367cab_get_frontend(fe, p); > > - default: > > + ret = stv0367cab_get_frontend(fe, p); > > break; > > + default: > > + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + return ret; > > } > > > > - return -EINVAL; > > + /* read fe lock status */ > > + if (!ret) > > + ret = stv0367ddb_read_status(fe, &status); > > + > > + /* stop if get_frontend failed or if demod isn't locked */ > > + if (ret || !(status & FE_HAS_LOCK)) { > > + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; > > + return ret; > > + } > > Requiring LOCK for strength and cnr sounds wrong. Demod usually > calculates strength from IF and RF AGC and those are available even > there is no signal at all (demod set those gains to max on that case). > CNR is pretty often available when inner FEC (viterbi, LDPC) is on sync. > > And for ber and per you need outer fec (reed-solomon, bch) too which is > FE_HAS_SYNC flag on api. ber is error bit and count after inner fec, per > is error packet and count after outer fec. Usually ber is counted as a > bits and per is counted as a 204 ts packets. Re ber/per, note that I don't have any register documentation available, everything has been gathered from this and from DD's stv0367dd driver. That said, the same applies to FE_HAS_SYNC. This driver currently only reports FE_HAS_LOCK for both OFDM and QAM operation modes, see L1503 (OFDM) and L2152. In stv0367dd, lock state acquisition is a bit more detailed. For the ddb-parts though, I even had to implement a var which carries the register which tells us in QAM mode where to acquire the lockstate from, so I don't want to blindly carry over that code since this will risk breakage of all other consumers of the stv0367 demod driver and thus the card support, neither do I want to additionally port over the read_status code since this will result in unneeded duplication of things. So atm things won
[PATCH] [media] ddbridge: use dev_* macros in favor of printk
From: Daniel Scheller Side effect: KERN_DEBUG messages aren't written to the kernel log anymore. This also improves the tda18212_ping reporting a bit so users know that if pinging wasn't successful, bad things will happen. Since in module_init_ddbridge() there's no dev yet, pr_info is used instead. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-core.c | 78 ++ 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9420479bee9a..540a121eadd6 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -17,6 +17,8 @@ * http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -124,10 +126,10 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); if (stat == 0) { - printk(KERN_ERR "I2C timeout\n"); + dev_err(&dev->pdev->dev, "I2C timeout\n"); { /* MSI debugging*/ u32 istat = ddbreadl(INTERRUPT_STATUS); - printk(KERN_ERR "IRS %08x\n", istat); + dev_err(&dev->pdev->dev, "IRS %08x\n", istat); ddbwritel(istat, INTERRUPT_ACK); } return -EIO; @@ -533,7 +535,7 @@ static u32 ddb_input_avail(struct ddb_input *input) off = (stat & 0x7ff) << 7; if (ctrl & 4) { - printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); + dev_err(&dev->pdev->dev, "IA %d %d %08x\n", idx, off, ctrl); ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); return 0; } @@ -611,6 +613,7 @@ static int demod_attach_drxk(struct ddb_input *input) struct i2c_adapter *i2c = &input->port->i2c->adap; struct dvb_frontend *fe; struct drxk_config config; + struct device *dev = &input->port->dev->pdev->dev; memset(&config, 0, sizeof(config)); config.microcode_name = "drxk_a3.mc"; @@ -619,7 +622,7 @@ static int demod_attach_drxk(struct ddb_input *input) fe = input->fe = dvb_attach(drxk_attach, &config, i2c); if (!input->fe) { - printk(KERN_ERR "No DRXK found!\n"); + dev_err(dev, "No DRXK found!\n"); return -ENODEV; } fe->sec_priv = input; @@ -632,12 +635,13 @@ static int tuner_attach_tda18271(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; struct dvb_frontend *fe; + struct device *dev = &input->port->dev->pdev->dev; if (input->fe->ops.i2c_gate_ctrl) input->fe->ops.i2c_gate_ctrl(input->fe, 1); fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); + dev_err(dev, "No TDA18271 found!\n"); return -ENODEV; } if (input->fe->ops.i2c_gate_ctrl) @@ -670,13 +674,14 @@ static struct stv0367_config ddb_stv0367_config[] = { static int demod_attach_stv0367(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; + struct device *dev = &input->port->dev->pdev->dev; /* attach frontend */ input->fe = dvb_attach(stv0367ddb_attach, &ddb_stv0367_config[(input->nr & 1)], i2c); if (!input->fe) { - printk(KERN_ERR "stv0367ddb_attach failed (not found?)\n"); + dev_err(dev, "stv0367ddb_attach failed (not found?)\n"); return -ENODEV; } @@ -690,17 +695,19 @@ static int demod_attach_stv0367(struct ddb_input *input) static int tuner_tda18212_ping(struct ddb_input *input, unsigned short adr) { struct i2c_adapter *adapter = &input->port->i2c->adap; + struct device *dev = &input->port->dev->pdev->dev; + u8 tda_id[2]; u8 subaddr = 0x00; - printk(KERN_DEBUG "stv0367-tda18212 tuner ping\n"); + dev_dbg(dev, "stv0367-tda18212 tuner ping\n"); if (input->fe->ops.i2c_gate_ctrl) input->fe->ops.i2c_gate_ctrl(input->fe, 1); if (i2c_read_regs(adapter, adr, subaddr, tda_id, sizeof(tda_id)) < 0) - printk(KERN_DEBUG "tda18212 ping 1 fail\n"); +
Re: [PATCH 3/4] [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T
Am Wed, 21 Jun 2017 09:30:27 +0300 schrieb Antti Palosaari : > On 06/20/2017 08:45 PM, Daniel Scheller wrote: > > From: Daniel Scheller > > > > Add signal-to-noise-ratio as provided by the demodulator in decibel scale. > > QAM/DVB-C needs some intlog calculation to have usable dB values, OFDM/ > > DVB-T values from the demod look alright already and are provided as-is. > > > > Signed-off-by: Daniel Scheller > > --- > > drivers/media/dvb-frontends/stv0367.c | 33 > > + > > 1 file changed, 33 insertions(+) > > > > diff --git a/drivers/media/dvb-frontends/stv0367.c > > b/drivers/media/dvb-frontends/stv0367.c > > index bb498f942ebd..0b13a407df23 100644 > > --- a/drivers/media/dvb-frontends/stv0367.c > > +++ b/drivers/media/dvb-frontends/stv0367.c > > @@ -25,6 +25,8 @@ > > #include > > #include > > > > +#include "dvb_math.h" > > + > > #include "stv0367.h" > > #include "stv0367_defs.h" > > #include "stv0367_regs.h" > > @@ -33,6 +35,9 @@ > > /* Max transfer size done by I2C transfer functions */ > > #define MAX_XFER_SIZE 64 > > > > +/* snr logarithmic calc */ > > +#define INTLOG10X100(x) ((u32) (((u64) intlog10(x) * 100) >> 24)) > > + > > static int stvdebug; > > module_param_named(debug, stvdebug, int, 0644); > > > > @@ -3013,6 +3018,33 @@ static int stv0367ddb_read_status(struct > > dvb_frontend *fe, > > return -EINVAL; > > } > > > > +static void stv0367ddb_read_snr(struct dvb_frontend *fe) > > +{ > > + struct stv0367_state *state = fe->demodulator_priv; > > + struct dtv_frontend_properties *p = &fe->dtv_property_cache; > > + int cab_pwr; > > + u32 regval, tmpval, snrval = 0; > > + > > + switch (state->activedemod) { > > + case demod_ter: > > + snrval = stv0367ter_snr_readreg(fe); > > + break; > > + case demod_cab: > > + cab_pwr = stv0367cab_snr_power(fe); > > + regval = stv0367cab_snr_readreg(fe, 0); > > + > > + tmpval = (cab_pwr * 320) / regval; > > + snrval = ((tmpval != 0) ? INTLOG10X100(tmpval) : 0) * 100; > > How much there will be rounding errors due to that signal/noise > division? I would convert it to calculation of sums (tip logarithm > calculation rules). This is taken from stv0367dd aswell, the reported and calculated values are in 0.1dB precision. This and to not diverge any more from the "source" driver, I'd prefer to keep it how it is. These are just simple tuner cards anyway and by no means professional measurement gear, and should only give a more or less rough estimate on reception quality. E.g. my stv0367 cards report around 36dB SNR, whereas the cxd2841er reports ~37dB, compared to my DOCSIS modem, which reports 34dB on DOCSIS channels (another variant I had earlier even reported 39dB on the same channels), so... Even, we get way more precision than on the relative scale calc on the cab_read_snr functions which is in 10%-steps... > Also, that INTLOG10X100 is pretty much useless. Use just what > intlog10/intlog2 offers without yet again another conversion. Will check and experiment. Again, taken from stv0367dd :-) -- Best regards, Daniel Scheller -- https://github.com/herrnst
Re: [PATCH] [media] ddbridge: use dev_* macros in favor of printk
Am Wed, 21 Jun 2017 14:08:08 -0300 schrieb Mauro Carvalho Chehab : > Em Wed, 21 Jun 2017 18:53:47 +0200 > Daniel Scheller escreveu: > > > From: Daniel Scheller > > > > Side effect: KERN_DEBUG messages aren't written to the kernel log anymore. > > This also improves the tda18212_ping reporting a bit so users know that if > > pinging wasn't successful, bad things will happen. > > > > Since in module_init_ddbridge() there's no dev yet, pr_info is used > > instead. > > > > Signed-off-by: Daniel Scheller > > --- > > drivers/media/pci/ddbridge/ddbridge-core.c | 78 > > ++ > > 1 file changed, 46 insertions(+), 32 deletions(-) > > > > diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c > > b/drivers/media/pci/ddbridge/ddbridge-core.c > > index 9420479bee9a..540a121eadd6 100644 > > --- a/drivers/media/pci/ddbridge/ddbridge-core.c > > +++ b/drivers/media/pci/ddbridge/ddbridge-core.c > > @@ -17,6 +17,8 @@ > > * http://www.gnu.org/copyleft/gpl.html > > */ > > > > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt > > + > > I guess this is a left over from the old patch. When you use dev_foo, > it will get the driver's name from dev->name. So, no need to do the > above. I intentionally left this in for the pr_info used in module_init_ddbridge(). If you prefer, we can ofc probably also leave this as printk like printk(KERN_INFO KBUILD_MODNAME ": Digital..."); IMHO, we should also have the modname info there aswell, especially when thinking of a possible ddbridge-legacy, so users see what's loaded. Best regards, Daniel Scheller -- https://github.com/herrnst
[PATCH v2 0/4] STV0367/DDB DVBv5 signal statistics
From: Daniel Scheller This series adds DVBv5 statistics support to the new DDB codepath of the stv0367 demodulator driver. The changes utilise already existing functionality (in form of register readouts), but wraps the reads in separate functions so the existing relative scale reporting can be kept as-is, while adding the v5 stats in dB scale where appropriate. >From my own testing: Reported values look approx. the same as those reported by the cxd2841er driver for both -C and -T. Changes from v1 to v2: - INTLOG10X100() macro for QAM SNR calculation removed and replaced by directly utilising intlog2 plus a div - factored statistics collection into *_read_status() - prevent a possible division by zero (though requires ridiculously good SNR to trigger) - _read_status() doesn't return -EINVAL anymore if no demod state is set, prevents falsely reported errors from inquiries of userspace tools Daniel Scheller (4): [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks [media] dvb-frontends/stv0367: split SNR determination into functions [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T [media] dvb-frontends/stv0367: DVB-C signal strength statistics drivers/media/dvb-frontends/stv0367.c | 178 -- 1 file changed, 148 insertions(+), 30 deletions(-) -- 2.13.0
[PATCH v2 2/4] [media] dvb-frontends/stv0367: split SNR determination into functions
From: Daniel Scheller The read_snr() functions currently do some magic to return relative scale values when called. Split out register readouts into separate functions so the functionality can be reused in some other way. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 68 +-- 1 file changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 8ba15dc339f8..f8e9cceed04e 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -1437,7 +1437,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe, return 0; } -static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) +static u32 stv0367ter_snr_readreg(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; u32 snru32 = 0; @@ -1453,10 +1453,16 @@ static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) cpt++; } - snru32 /= 10;/*average on 10 values*/ - *snr = snru32 / 1000; + return snru32; +} + +static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + u32 snrval = stv0367ter_snr_readreg(fe); + + *snr = snrval / 1000; return 0; } @@ -2702,51 +2708,61 @@ static int stv0367cab_read_strength(struct dvb_frontend *fe, u16 *strength) return 0; } -static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) +static int stv0367cab_snr_power(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; - u32 noisepercentage; enum stv0367cab_mod QAMSize; - u32 regval = 0, temp = 0; - int power, i; QAMSize = stv0367_readbits(state, F367CAB_QAM_MODE); switch (QAMSize) { case FE_CAB_MOD_QAM4: - power = 21904; - break; + return 21904; case FE_CAB_MOD_QAM16: - power = 20480; - break; + return 20480; case FE_CAB_MOD_QAM32: - power = 23040; - break; + return 23040; case FE_CAB_MOD_QAM64: - power = 21504; - break; + return 21504; case FE_CAB_MOD_QAM128: - power = 23616; - break; + return 23616; case FE_CAB_MOD_QAM256: - power = 21760; - break; - case FE_CAB_MOD_QAM512: - power = 1; - break; + return 21760; case FE_CAB_MOD_QAM1024: - power = 21280; - break; + return 21280; default: - power = 1; break; } + return 1; +} + +static int stv0367cab_snr_readreg(struct dvb_frontend *fe, int avgdiv) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 regval = 0; + int i; + for (i = 0; i < 10; i++) { regval += (stv0367_readbits(state, F367CAB_SNR_LO) + 256 * stv0367_readbits(state, F367CAB_SNR_HI)); } - regval /= 10; /*for average over 10 times in for loop above*/ + if (avgdiv) + regval /= 10; + + return regval; +} + +static int stv0367cab_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct stv0367_state *state = fe->demodulator_priv; + u32 noisepercentage; + u32 regval = 0, temp = 0; + int power; + + power = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 1); + if (regval != 0) { temp = power * (1 << (3 + stv0367_readbits(state, F367CAB_SNR_PER))); -- 2.13.0
[PATCH v2 4/4] [media] dvb-frontends/stv0367: DVB-C signal strength statistics
From: Daniel Scheller Provide QAM/DVB-C signal strength in decibel scale. Values returned from stv0367cab_get_rf_lvl() are good but need to be multiplied as they're in 1dBm precision. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 21 + 1 file changed, 21 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index d3be25bc1002..bac6707957a3 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2998,6 +2998,25 @@ static int stv0367ddb_set_frontend(struct dvb_frontend *fe) return -EINVAL; } +static void stv0367ddb_read_signal_strength(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + s32 signalstrength; + + switch (state->activedemod) { + case demod_cab: + signalstrength = stv0367cab_get_rf_lvl(state) * 1000; + break; + default: + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->strength.stat[0].scale = FE_SCALE_DECIBEL; + p->strength.stat[0].uvalue = signalstrength; +} + static void stv0367ddb_read_snr(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; @@ -3075,12 +3094,14 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, /* stop if demod isn't locked */ if (!(*status & FE_HAS_LOCK)) { + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; return ret; } stv0367ddb_read_snr(fe); + stv0367ddb_read_signal_strength(fe); stv0367ddb_read_ucblocks(fe); return 0; -- 2.13.0
[PATCH v2 1/4] [media] dvb-frontends/stv0367: initial DDB DVBv5 stats, implement ucblocks
From: Daniel Scheller This adds the basics to stv0367ddb_read_status() to be able to properly provide signal statistics in DVBv5 format. Also adds UCB readout and provides those values. Also, don't return -EINVAL in ddb_read_status() if active_demod_state indicates no delivery system. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 54 --- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index e726c2e00460..8ba15dc339f8 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2980,21 +2980,59 @@ static int stv0367ddb_set_frontend(struct dvb_frontend *fe) return -EINVAL; } +static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + u32 ucblocks = 0; + + switch (state->activedemod) { + case demod_ter: + stv0367ter_read_ucblocks(fe, &ucblocks); + break; + case demod_cab: + stv0367cab_read_ucblcks(fe, &ucblocks); + break; + default: + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->block_error.stat[0].scale = FE_SCALE_COUNTER; + p->block_error.stat[0].uvalue = ucblocks; +} + static int stv0367ddb_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int ret; switch (state->activedemod) { case demod_ter: - return stv0367ter_read_status(fe, status); + ret = stv0367ter_read_status(fe, status); + break; case demod_cab: - return stv0367cab_read_status(fe, status); - default: + ret = stv0367cab_read_status(fe, status); break; + default: + return 0; } - return -EINVAL; + /* stop and report on *_read_status failure */ + if (ret) + return ret; + + /* stop if demod isn't locked */ + if (!(*status & FE_HAS_LOCK)) { + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return ret; + } + + stv0367ddb_read_ucblocks(fe); + + return 0; } static int stv0367ddb_get_frontend(struct dvb_frontend *fe, @@ -3035,6 +3073,7 @@ static int stv0367ddb_sleep(struct dvb_frontend *fe) static int stv0367ddb_init(struct stv0367_state *state) { struct stv0367ter_state *ter_state = state->ter_state; + struct dtv_frontend_properties *p = &state->fe.dtv_property_cache; stv0367_writereg(state, R367TER_TOPCTRL, 0x10); @@ -3109,6 +3148,13 @@ static int stv0367ddb_init(struct stv0367_state *state) ter_state->first_lock = 0; ter_state->unlock_counter = 2; + p->strength.len = 1; + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->cnr.len = 1; + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + p->block_error.len = 1; + p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; } -- 2.13.0
[PATCH v2 3/4] [media] dvb-frontends/stv0367: SNR DVBv5 statistics for DVB-C and T
From: Daniel Scheller Add signal-to-noise-ratio as provided by the demodulator in decibel scale. QAM/DVB-C needs some intlog calculation to have usable dB values, OFDM/ DVB-T values from the demod look alright already and are provided as-is. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 35 +++ 1 file changed, 35 insertions(+) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index f8e9cceed04e..d3be25bc1002 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -25,6 +25,8 @@ #include #include +#include "dvb_math.h" + #include "stv0367.h" #include "stv0367_defs.h" #include "stv0367_regs.h" @@ -2996,6 +2998,37 @@ static int stv0367ddb_set_frontend(struct dvb_frontend *fe) return -EINVAL; } +static void stv0367ddb_read_snr(struct dvb_frontend *fe) +{ + struct stv0367_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *p = &fe->dtv_property_cache; + int cab_pwr; + u32 regval, tmpval, snrval = 0; + + switch (state->activedemod) { + case demod_ter: + snrval = stv0367ter_snr_readreg(fe); + break; + case demod_cab: + cab_pwr = stv0367cab_snr_power(fe); + regval = stv0367cab_snr_readreg(fe, 0); + + /* prevent division by zero */ + if (!regval) + snrval = 0; + + tmpval = (cab_pwr * 320) / regval; + snrval = ((tmpval != 0) ? (intlog2(tmpval) / 5581) : 0); + break; + default: + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return; + } + + p->cnr.stat[0].scale = FE_SCALE_DECIBEL; + p->cnr.stat[0].uvalue = snrval; +} + static void stv0367ddb_read_ucblocks(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; @@ -3042,10 +3075,12 @@ static int stv0367ddb_read_status(struct dvb_frontend *fe, /* stop if demod isn't locked */ if (!(*status & FE_HAS_LOCK)) { + p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; return ret; } + stv0367ddb_read_snr(fe); stv0367ddb_read_ucblocks(fe); return 0; -- 2.13.0
Re: [PATCH v2 0/4] STV0367/DDB DVBv5 signal statistics
Am Wed, 21 Jun 2017 21:45:40 +0200 schrieb Daniel Scheller : > From: Daniel Scheller > > This series adds DVBv5 statistics support to the new DDB codepath of the > stv0367 demodulator driver. > > The changes utilise already existing functionality (in form of register > readouts), but wraps the reads in separate functions so the existing > relative scale reporting can be kept as-is, while adding the v5 stats > in dB scale where appropriate. > > From my own testing: Reported values look approx. the same as those > reported by the cxd2841er driver for both -C and -T. > > Changes from v1 to v2: > - INTLOG10X100() macro for QAM SNR calculation removed and replaced by >directly utilising intlog2 plus a div > - factored statistics collection into *_read_status() > - prevent a possible division by zero (though requires ridiculously good >SNR to trigger) > - _read_status() doesn't return -EINVAL anymore if no demod state is set, >prevents falsely reported errors from inquiries of userspace tools Antti, FYI: statistics inquiry now lives in read_status(), didn't see any functional differences or problems due to this, so if your're comfortable with this, this variant works fine for me. Also, INTLOG10X100 is history, this even gave an improvement of two decimals of precision in dtv_property_cache, which will definitely work for everyone - we're still no scientific pro-measurement-gear. Readout of stats are still limited to FE_HAS_LOCK though, since, as explained, this is the only bit we'll receive at the moment. Best regards, Daniel Scheller -- https://github.com/herrnst
Re: [PATCH] [media] ddbridge: use dev_* macros in favor of printk
Am Wed, 21 Jun 2017 22:20:35 +0300 schrieb Antti Palosaari : > On 06/21/2017 08:20 PM, Mauro Carvalho Chehab wrote: > > Em Wed, 21 Jun 2017 19:14:40 +0200 > > Daniel Scheller escreveu: > > > >> I intentionally left this in for the pr_info used in > >> module_init_ddbridge(). If you prefer, we can ofc probably also leave this > >> as printk like > >> > >> printk(KERN_INFO KBUILD_MODNAME ": Digital..."); > > > > Ah, OK! > > But why you even need it? Probe should be first place you need to print > something and there is always proper device pointer. This will be printed whenever the module is loaded. When in ddb_probe, you won't notice ever if the module is loaded for whatever reason if no DD card is there, or a card is present which isn't supported, and printed multiple times if you have more than one supported card (imagine a CTv6 plus module, and a CI Bridge, which gets common these days). Let's keep it as it is, please. Regards, Daniel Scheller -- https://github.com/herrnst
[PATCH] [media] dvb-frontends/stv0367: deduplicate DDB dvb_frontend_ops caps
From: Daniel Scheller Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0367.c | 13 + 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index e726c2e00460..b42b99ad4d3f 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -3126,15 +3126,12 @@ static const struct dvb_frontend_ops stv0367ddb_ops = { 0x400 |/* FE_CAN_QAM_4 */ FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | - FE_CAN_QAM_256 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | /* DVB-T */ - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | - FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER | - FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_RECOVER | FE_CAN_INVERSION_AUTO | FE_CAN_MUTE_TS }, .release = stv0367_release, -- 2.13.0
Re: DD support improvements (was: Re: [PATCH v3 00/13] stv0367/ddbridge: support CTv6/FlexCT hardware)
Am Tue, 20 Jun 2017 16:10:43 -0300 schrieb Mauro Carvalho Chehab : > Em Tue, 20 Jun 2017 20:41:21 +0200 > Daniel Scheller escreveu: > > > Not sure about Thomas, but I know that Jasmin doesn't own and/ore uses > > such cards. However, for upcoming patches, I'll try to drag people to > > the list for some comments, thanks for the pointer. > > Yeah, if you can drag people to help reviewing/testing (and even > coding), that would be really cool, as we'll be able to better > do our reviews. For the upcoming bigger changes around ddbridge and new demod/tuner drivers, I'll try to do so. Though this would mostly be for Tested-By's, but still. > > - Maybe for 4.14: Support for the CineS2 V7 and FlexV4 line of > > cards/modules. This mainly involves a new demod driver (stv0910) and > > a new tuner driver (stv6111). Permissions for this are cleared with > > Ralph already. The glue code needed in ddbridge is rather easy, and > > as some ground work (mostly the MachXO2 support from the 2841 series) > > is now in, the changes are quite small. Patches are ready so far but > > need more cleanup (checkpatch fixes, camel case and such things). > > Please try to sync it with Ralph, in a way that his code won't > diverge from the upstream one, as this will make easier for both > sides to keep the Kernel in track with driver improvements. This is not going to work. DD (Ralph and Manfred Voelkel) sort of maintain a shared code base between their Windows driver and the Linux kernel driver sources. While they didn't explicitely stated this, this can be noticed by the remarks and commented code in their OSS code, and the commit messages in their dddvb GIT (e.g. "sync with windows driver"). I've already cleaned up a lot of this (I believe no one wants to see such stuff in the linux kernel tree). If we're additionally going to replace all things camel case, with some more cleaning and maybe code shuffling after like a V4 patch series, those two sources are out of sync in a way that no automatic sync by applying patches will be possible anymore. So, pushing from vendor's upstream to the kernel seems to be the only option, and in fact, if the whole driver/package stack completely lives in the kernel sources, maybe DD even decide to directly commit upstream (kernel) again. Putting Ralph into "To:", really like to hear an opinion from him on this whole subject. > > - The "big" ddbridge update. I'm thinking of two ways to do this: > > > > * Do this in one commit, being a huge code bump, bringing ddbridge to > > version 0.9.28 (as per vendor versioning). This is mostly ready and > > successful in use by many testers and in my Gentoo ddbridge kernel > > sources overlay. Should get some more cleanups though (still some > > GTL link bits left which are not needed), and all fixes which went > > to the in-kernel driver like __user annotations need to be put back > > in. Big drawback: A mess to review. > > > > * Try to tear apart most if not all upstream vendor driver tar > > archives and recreate individual patches out of this. For > > reference, we need to go from what is in the kernel which is > > something inbetween v0.5 and v0.8 up to and including version > > 0.9.29. I'm currently working on this from time to time, and I can > > assure you that this is an extremely tedious and unthankful thing > > to do (currently nearly done with 0.9.9b, approx. 20 releases > > left). This might be better to review, but this will also result in > > something like 100-200 commits, without guarantee of having > > everything correct. > > The second approach is preferred, but, as you said, it is a very > complex task, and has bad effect that, at the time you're updating > it, the DD driver will be changed. I'd welcome it if we could put approach two somewhat aside for at least the reasons outlined :) > The first approach will require some things to work, though: > > - the "legacy" driver should be kept at the Kernel for some time, > in order to provide a "fall back" for those that find issues with > the new version; From what can be gathered from forums and such, the current ("upstream") version doesn't show some (if any) issues. Though I'm aware that MSI interrupts are still an issue on a lot of hardware platforms, but disabling that option by default in the driver and toggling this via a Kconfig option works around this, since w/o MSI things work like a charm. Thats a problem that needs to be resolved by the vendor though. Still, I understand you that y
[PATCH] [media] dvb-frontends/cxd2841er: require FE_HAS_SYNC for agc readout
From: Daniel Scheller When the demod driver puts the demod into sleep or shutdown state and it's status is then polled e.g. via "dvb-fe-tool -m", i2c errors are printed to the kernel log. If the last delsys was DVB-T/T2: cxd2841er: i2c wr failed=-5 addr=6c reg=00 len=1 cxd2841er: i2c rd failed=-5 addr=6c reg=26 and if it was DVB-C: cxd2841er: i2c wr failed=-5 addr=6c reg=00 len=1 cxd2841er: i2c rd failed=-5 addr=6c reg=49 This happens when read_status unconditionally calls into the read_signal_strength() function which triggers the read_agc_gain_*() functions, where these registered are polled. This isn't a critical thing since when the demod is active again, no more such errors are logged, however this might make users suspecting defects. Fix this by requiring fe_status FE_HAS_SYNC to be sure the demod is not put asleep or shut down. If FE_HAS_SYNC isn't set, additionally set the strength scale to NOT_AVAILABLE. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/cxd2841er.c | 5 - 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 08f67d60a7d9..9fff031436f1 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -3279,7 +3279,10 @@ static int cxd2841er_get_frontend(struct dvb_frontend *fe, else if (priv->state == STATE_ACTIVE_TC) cxd2841er_read_status_tc(fe, &status); - cxd2841er_read_signal_strength(fe); + if (status & FE_HAS_SYNC) + cxd2841er_read_signal_strength(fe); + else + p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; if (status & FE_HAS_LOCK) { cxd2841er_read_snr(fe); -- 2.13.0
[PATCH] [media] ddbridge: make (ddb)readl in while-loops fail-safe
From: Daniel Scheller Reported by smatch: drivers/media/pci/ddbridge/ddbridge-core.c:1246 input_tasklet() warn: this loop depends on readl() succeeding drivers/media/pci/ddbridge/ddbridge-core.c:1768 flashio() warn: this loop depends on readl() succeeding drivers/media/pci/ddbridge/ddbridge-core.c:1788 flashio() warn: this loop depends on readl() succeeding Fix this by introducing safe_ddbreadl() which will wrap ddbreadl and checks for all bits set in the return which indicates failure, and return 0 in that case. Usable as drop-in-replacement in all affected while loops w/o having to change the logic. Signed-off-by: Daniel Scheller --- drivers/media/pci/ddbridge/ddbridge-core.c | 23 ++- 1 file changed, 18 insertions(+), 5 deletions(-) TODO: fix up the printk if https://patchwork.linuxtv.org/patch/42034/ eventually gets merged. Assuming that (uint)-1 is really a reserved return value in iomem (as mentioned, I'm not that much into kernel and io related things) and it isn't possible to expect 0x by definition, this should be good. Quickly tested with four tuners and four streams running in parallel without issues. diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 9420479bee9a..cf7a6b0532dc 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -114,6 +114,19 @@ static int i2c_write_reg(struct i2c_adapter *adap, u8 adr, return i2c_write(adap, adr, msg, 2); } +static inline u32 safe_ddbreadl(struct ddb *dev, u32 adr) +{ + u32 val = ddbreadl(adr); + + /* (ddb)readl returns (uint)-1 (all bits set) on failure, catch that */ + if (val == ~0) { + printk(KERN_ERR "ddbreadl failure, adr=%08x\n", adr); + return 0; + } + + return val; +} + static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) { struct ddb *dev = i2c->dev; @@ -1243,7 +1256,7 @@ static void input_tasklet(unsigned long data) if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) printk(KERN_ERR "Overflow input %d\n", input->nr); while (input->cbuf != ((input->stat >> 11) & 0x1f) - || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr { + || (4 & safe_ddbreadl(dev, DMA_BUFFER_CONTROL(input->nr { dvb_dmx_swfilter_packets(&input->demux, input->vbuf[input->cbuf], input->dma_buf_size / 188); @@ -1765,7 +1778,7 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) wbuf += 4; wlen -= 4; ddbwritel(data, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) + while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) ; } @@ -1785,7 +1798,7 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) if (shift) data <<= shift; ddbwritel(data, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) + while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) ; if (!rlen) { @@ -1797,7 +1810,7 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) while (rlen > 4) { ddbwritel(0x, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) + while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) ; data = ddbreadl(SPI_DATA); *(u32 *) rbuf = swab32(data); @@ -1806,7 +1819,7 @@ static int flashio(struct ddb *dev, u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen) } ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); ddbwritel(0x, SPI_DATA); - while (ddbreadl(SPI_CONTROL) & 0x0004) + while (safe_ddbreadl(dev, SPI_CONTROL) & 0x0004) ; data = ddbreadl(SPI_DATA); -- 2.13.0
[PATCH 0/9] STV0910/STV6111 drivers, ddbridge CineS2 V7 support
From: Daniel Scheller For Linux 4.14. This series adds drivers for the ST STV0910 DVB-S/S2 demodulator ICs and the ST STV6111 DVB-S/S2 tuners, and utilises them to enable ddbridge to support the current line of Digital Devices DVB-S/S2 hardware (e.g. Cine S2 V7/V7A adapters, DuoFlex S2 V4 addon modules and maybe more, with similar components). The two new drivers have been picked up from Digital Devices' vendor- provided dddvb driver package, as of release 0.9.29. Permission to reuse (and mainline) them was formally granted by Ralph Metzler . Drivers have been cleaned up alot (formatting fixes, dead code removal, features depending on not-yet-available API changes removed). Checkpatch complaints left: WARNING: please write a paragraph that describes the config symbol fully #39: FILE: drivers/media/dvb-frontends/Kconfig:31: +config DVB_STV0910 Not sure what checkpatch demands, since a module description exists in Kconfig... Applies to the stv6111 aswell. WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? #64: new file mode 100644 See below. WARNING: 'VALIDE' may be misspelled - perhaps 'VALID'? #3314: FILE: drivers/media/dvb-frontends/stv0910_regs.h:1467: +#define FSTV0910_P2_NOSRAM_VALIDE 0xf30e0004 Picked from upstream. Since I'm not sure if this really is a mistake (maybe the hardware vendor really wants to name the reg like this?) so kept as-is. Also, all uppercase writing an camel case are still there yet, and if you don't ultimately insist of having this changed (there are drivers all over the place which have uppercase vars), I'll prefer to keep it like it is at the moment to not diverge even more from upstream, that'll ease syncing later on that way. Else, I can change this ofc. Patch 2 is a fix for an issue found while preparing this series for posting, and was in parallel submitted to the vendor's GIT repository. Patch 8 eventually needs fixup (printk -> dev_*) wrt https://patchwork.linuxtv.org/patch/42034/ Regarding MAINTAINERS and maintainership: I already offered to volunteer to regularly check for upstream updates and sync them to mainline, as outlined at http://www.mail-archive.com/linux-media@vger.kernel.org/msg114469.html . If this qualifies for an entry in MAINTAINERS, then that one's missing. Please advise. Mauro, I assume you're the one who reviews this (since these are new drivers). It'd be very great to have this in for 4.14 to tackle the ddbridge bump for 4.15. Daniel Scheller (9): [media] dvb-frontends: add ST STV0910 DVB-S/S2 demodulator frontend driver [media] dvb-frontends/stv0910: Fix possible buffer overflow [media] dvb-frontends/stv0910: add multistream (ISI) and PLS capabilities [media] dvb-frontends/stv0910: Fix signal strength reporting [media] dvb-frontends/stv0910: Add missing set_frontend fe-op [media] dvb-frontends: add ST STV6111 DVB-S/S2 tuner frontend driver [media] ddbridge: return stv09xx id in port_has_stv0900_aa() [media] ddbridge: support for CineS2 V7(A) and DuoFlex S2 V4 hardware [media] ddbridge: stv0910 single demod mode module option drivers/media/dvb-frontends/Kconfig| 18 + drivers/media/dvb-frontends/Makefile |2 + drivers/media/dvb-frontends/stv0910.c | 1765 +++ drivers/media/dvb-frontends/stv0910.h | 32 + drivers/media/dvb-frontends/stv0910_regs.h | 4759 drivers/media/dvb-frontends/stv6111.c | 675 drivers/media/dvb-frontends/stv6111.h | 20 + drivers/media/pci/ddbridge/Kconfig |4 + drivers/media/pci/ddbridge/ddbridge-core.c | 149 +- drivers/media/pci/ddbridge/ddbridge.h |2 + 10 files changed, 7418 insertions(+), 8 deletions(-) create mode 100644 drivers/media/dvb-frontends/stv0910.c create mode 100644 drivers/media/dvb-frontends/stv0910.h create mode 100644 drivers/media/dvb-frontends/stv0910_regs.h create mode 100644 drivers/media/dvb-frontends/stv6111.c create mode 100644 drivers/media/dvb-frontends/stv6111.h -- 2.13.0
[PATCH 2/9] [media] dvb-frontends/stv0910: Fix possible buffer overflow
From: Daniel Scheller Fixes smatch error: drivers/media/dvb-frontends/stv0910.c:715 DVBS2_nBCH() error: buffer overflow 'nBCH[FECType]' 2 <= 28 Also, fixes the nBCH array table by adding the DUMMY_PLF element at the top to match the enums (table element order was off by one before). Patch sent upstream aswell. Cc: Ralph Metzler Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0910.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index 8cb4b30f3a81..a5eac1a3a048 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -680,6 +680,7 @@ static int GetBitErrorRateS(struct stv *state, u32 *BERNumerator, static u32 DVBS2_nBCH(enum DVBS2_ModCod ModCod, enum DVBS2_FECType FECType) { static u32 nBCH[][2] = { + {0, 0}, /* DUMMY_PLF */ {16200, 3240}, /* QPSK_1_4, */ {21600, 5400}, /* QPSK_1_3, */ {25920, 6480}, /* QPSK_2_5, */ @@ -712,7 +713,7 @@ static u32 DVBS2_nBCH(enum DVBS2_ModCod ModCod, enum DVBS2_FECType FECType) if (ModCod >= DVBS2_QPSK_1_4 && ModCod <= DVBS2_32APSK_9_10 && FECType <= DVBS2_16K) - return nBCH[FECType][ModCod]; + return nBCH[ModCod][FECType]; return 64800; } -- 2.13.0
[PATCH 3/9] [media] dvb-frontends/stv0910: add multistream (ISI) and PLS capabilities
From: Daniel Scheller Implements stream_id filter and scrambling code setup in Start() and also sets FE_CAN_MULTISTREAM in frontend_ops. This enables the driver to properly receive and handle multistream transponders, functionality has been reported working fine by testers with access to such streams, in conjunction with VDR on the userspace side. The code snippet originates from the original vendor's dddvb driver package and has been made working properly with the current in-kernel DVB core API. Signed-off-by: Daniel Scheller --- drivers/media/dvb-frontends/stv0910.c | 32 ++-- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c index a5eac1a3a048..999ee6a8ea23 100644 --- a/drivers/media/dvb-frontends/stv0910.c +++ b/drivers/media/dvb-frontends/stv0910.c @@ -124,9 +124,7 @@ struct stv { int isVCM; u32 CurScramblingCode; - u32 ForceScramblingCode; u32 ScramblingCode; - u32 DefaultInputStreamID; u32 LastBERNumerator; u32 LastBERDenominator; @@ -972,6 +970,7 @@ static int Start(struct stv *state, struct dtv_frontend_properties *p) s32 Freq; u8 regDMDCFGMD; u16 symb; + u32 ScramblingCode = 1; if (p->symbol_rate < 10 || p->symbol_rate > 7000) return -EINVAL; @@ -985,6 +984,28 @@ static int Start(struct stv *state, struct dtv_frontend_properties *p) init_search_param(state); + if (p->stream_id != NO_STREAM_ID_FILTER) { + /* Backwards compatibility to "crazy" API. +* PRBS X root cannot be 0, so this should always work. +*/ + if (p->stream_id & 0xff00) + ScramblingCode = p->stream_id >> 8; + write_reg(state, RSTV0910_P2_ISIENTRY + state->regoff, + p->stream_id & 0xff); + write_reg(state, RSTV0910_P2_ISIBITENA + state->regoff, + 0xff); + } + + if (ScramblingCode != state->CurScramblingCode) { + write_reg(state, RSTV0910_P2_PLROOT0 + state->regoff, + ScramblingCode & 0xff); + write_reg(state, RSTV0910_P2_PLROOT1 + state->regoff, + (ScramblingCode >> 8) & 0xff); + write_reg(state, RSTV0910_P2_PLROOT2 + state->regoff, + (ScramblingCode >> 16) & 0x07); + state->CurScramblingCode = ScramblingCode; + } + if (p->symbol_rate <= 100) { /* SR <=1Msps */ state->DemodTimeout = 3000; state->FecTimeout = 2000; @@ -1643,7 +1664,8 @@ static struct dvb_frontend_ops stv0910_ops = { .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | FE_CAN_QPSK | - FE_CAN_2G_MODULATION + FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .sleep = sleep, .release= release, @@ -1687,9 +1709,7 @@ struct dvb_frontend *stv0910_attach(struct i2c_adapter *i2c, state->SearchRange = 1600; state->DEMOD = 0x10; /* Inversion : Auto with reset to 0 */ state->ReceiveMode = Mode_None; - state->CurScramblingCode = (u32) -1; - state->ForceScramblingCode = (u32) -1; - state->DefaultInputStreamID = (u32) -1; + state->CurScramblingCode = (~0U); state->single = cfg->single ? 1 : 0; base = match_base(i2c, cfg->adr); -- 2.13.0