diff options
Diffstat (limited to 'drivers/media/usb/cx231xx/cx231xx-dvb.c')
| -rw-r--r-- | drivers/media/usb/cx231xx/cx231xx-dvb.c | 552 |
1 files changed, 295 insertions, 257 deletions
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index ee3eeeb600f8..0037b4b1381e 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1,30 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* DVB device driver for cx231xx Copyright (C) 2008 <srinivasa.deevi at conexant dot com> Based on em28xx driver - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx231xx.h" #include <linux/kernel.h> #include <linux/slab.h> +#include <media/dvbdev.h> +#include <media/dmxdev.h> +#include <media/dvb_demux.h> +#include <media/dvb_net.h> +#include <media/dvb_frontend.h> #include <media/v4l2-common.h> -#include <media/videobuf-vmalloc.h> #include <media/tuner.h> #include "xc5000.h" @@ -53,9 +45,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define CX231XX_DVB_NUM_BUFS 5 #define CX231XX_DVB_MAX_PACKETSIZE 564 #define CX231XX_DVB_MAX_PACKETS 64 +#define CX231XX_DVB_MAX_FRONTENDS 2 struct cx231xx_dvb { - struct dvb_frontend *frontend; + struct dvb_frontend *frontend[CX231XX_DVB_MAX_FRONTENDS]; /* feed count management */ struct mutex lock; @@ -68,7 +61,7 @@ struct cx231xx_dvb { struct dmx_frontend fe_hw; struct dmx_frontend fe_mem; struct dvb_net net; - struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_demod[2]; struct i2c_client *i2c_client_tuner; }; @@ -79,7 +72,7 @@ static struct s5h1432_config dvico_s5h1432_config = { .vsb_if = S5H1432_IF_4000, .inversion = S5H1432_INVERSION_OFF, .status_mode = S5H1432_DEMODLOCKING, - .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1432_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = { @@ -108,7 +101,7 @@ static struct s5h1411_config tda18271_s5h1411_config = { .qam_if = S5H1411_IF_4000, .inversion = S5H1411_INVERSION_ON, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct s5h1411_config xc5000_s5h1411_config = { .output_mode = S5H1411_SERIAL_OUTPUT, @@ -117,7 +110,7 @@ static struct s5h1411_config xc5000_s5h1411_config = { .qam_if = S5H1411_IF_3250, .inversion = S5H1411_INVERSION_OFF, .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, + .mpeg_timing = S5H1411_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK, }; static struct lgdt3305_config hcw_lgdt3305_config = { @@ -154,11 +147,9 @@ static struct tda18271_config pv_tda18271_config = { .small_i2c = TDA18271_03_BYTE_CHUNK_INIT, }; -static struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { - .i2c_addr = 0x59, +static const struct lgdt3306a_config hauppauge_955q_lgdt3306a_config = { .qam_if_khz = 4000, .vsb_if_khz = 3250, - .deny_i2c_rptr = 1, .spectral_inversion = 1, .mpeg_mode = LGDT3306A_MPEG_SERIAL, .tpclk_edge = LGDT3306A_TPCLK_RISING_EDGE, @@ -179,10 +170,10 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status) switch (status) { case -ENOENT: - errmsg = "unlinked synchronuously"; + errmsg = "unlinked synchronously"; break; case -ECONNRESET: - errmsg = "unlinked asynchronuously"; + errmsg = "unlinked asynchronously"; break; case -ENOSR: errmsg = "Buffer error (overrun)"; @@ -275,7 +266,7 @@ static int start_streaming(struct cx231xx_dvb *dvb) if (dev->USE_ISO) { dev_dbg(dev->dev, "DVB transfer mode is ISO.\n"); - cx231xx_set_alt_setting(dev, INDEX_TS1, 4); + cx231xx_set_alt_setting(dev, INDEX_TS1, 5); rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE); if (rc < 0) return rc; @@ -386,17 +377,17 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master); cfg.i2c_addr = addr; - if (!dev->dvb->frontend) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n", dev->name); return -EINVAL; } - fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg); + fe = dvb_attach(xc5000_attach, dev->dvb->frontend[0], &cfg); if (!fe) { dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name); - dvb_frontend_detach(dev->dvb->frontend); - dev->dvb->frontend = NULL; + dvb_frontend_detach(dev->dvb->frontend[0]); + dev->dvb->frontend[0] = NULL; return -EINVAL; } @@ -408,9 +399,9 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) { - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + if (dev->dvb && dev->dvb->frontend[0]) { - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; if (dops->set_analog_params != NULL) { struct analog_parameters params; @@ -421,7 +412,7 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq) /*params.audmode = ; */ /* Set the analog parameters to set the frequency */ - dops->set_analog_params(dev->dvb->frontend, ¶ms); + dops->set_analog_params(dev->dvb->frontend[0], ¶ms); } } @@ -433,15 +424,15 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev) { int status = 0; - if ((dev->dvb != NULL) && (dev->dvb->frontend != NULL)) { + if (dev->dvb && dev->dvb->frontend[0]) { - struct dvb_tuner_ops *dops = &dev->dvb->frontend->ops.tuner_ops; + struct dvb_tuner_ops *dops = &dev->dvb->frontend[0]->ops.tuner_ops; if (dops->init != NULL && !dev->xc_fw_load_done) { dev_dbg(dev->dev, "Reloading firmware for XC5000\n"); - status = dops->init(dev->dvb->frontend); + status = dops->init(dev->dvb->frontend[0]); if (status == 0) { dev->xc_fw_load_done = 1; dev_dbg(dev->dev, @@ -481,17 +472,32 @@ static int register_dvb(struct cx231xx_dvb *dvb, dvb_register_media_controller(&dvb->adapter, dev->media_dev); /* Ensure all frontends negotiate bus access */ - dvb->frontend->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + dvb->frontend[0]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; + if (dvb->frontend[1]) + dvb->frontend[1]->ops.ts_bus_ctrl = cx231xx_dvb_bus_ctrl; dvb->adapter.priv = dev; /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); + result = dvb_register_frontend(&dvb->adapter, dvb->frontend[0]); if (result < 0) { dev_warn(dev->dev, "%s: dvb_register_frontend failed (errno = %d)\n", dev->name, result); - goto fail_frontend; + goto fail_frontend0; + } + + if (dvb->frontend[1]) { + result = dvb_register_frontend(&dvb->adapter, dvb->frontend[1]); + if (result < 0) { + dev_warn(dev->dev, + "%s: 2nd dvb_register_frontend failed (errno = %d)\n", + dev->name, result); + goto fail_frontend1; + } + + /* MFE lock */ + dvb->adapter.mfe_shared = 1; } /* register demux stuff */ @@ -569,9 +575,14 @@ fail_fe_hw: fail_dmxdev: dvb_dmx_release(&dvb->demux); fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); + if (dvb->frontend[1]) + dvb_unregister_frontend(dvb->frontend[1]); + dvb_unregister_frontend(dvb->frontend[0]); +fail_frontend1: + if (dvb->frontend[1]) + dvb_frontend_detach(dvb->frontend[1]); +fail_frontend0: + dvb_frontend_detach(dvb->frontend[0]); dvb_unregister_adapter(&dvb->adapter); fail_adapter: return result; @@ -579,35 +590,37 @@ fail_adapter: static void unregister_dvb(struct cx231xx_dvb *dvb) { - struct i2c_client *client; dvb_net_release(&dvb->net); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); dvb_dmxdev_release(&dvb->dmxdev); dvb_dmx_release(&dvb->demux); - /* remove I2C tuner */ - client = dvb->i2c_client_tuner; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - /* remove I2C demod */ - client = dvb->i2c_client_demod; - if (client) { - module_put(client->dev.driver->owner); - i2c_unregister_device(client); - } - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); + if (dvb->frontend[1]) + dvb_unregister_frontend(dvb->frontend[1]); + dvb_unregister_frontend(dvb->frontend[0]); + if (dvb->frontend[1]) + dvb_frontend_detach(dvb->frontend[1]); + dvb_frontend_detach(dvb->frontend[0]); dvb_unregister_adapter(&dvb->adapter); + + /* remove I2C tuner */ + dvb_module_release(dvb->i2c_client_tuner); + dvb->i2c_client_tuner = NULL; + /* remove I2C demod(s) */ + dvb_module_release(dvb->i2c_client_demod[1]); + dvb->i2c_client_demod[1] = NULL; + dvb_module_release(dvb->i2c_client_demod[0]); + dvb->i2c_client_demod[0] = NULL; } static int dvb_init(struct cx231xx *dev) { - int result = 0; + int result; struct cx231xx_dvb *dvb; struct i2c_adapter *tuner_i2c; struct i2c_adapter *demod_i2c; + struct i2c_client *client; + struct i2c_adapter *adapter; if (!dev->board.has_dvb) { /* This device does not support the extension */ @@ -635,11 +648,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_CARRAERA: case CX231XX_BOARD_CNXT_RDE_250: - dev->dvb->frontend = dvb_attach(s5h1432_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, &dvico_s5h1432_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1432 front end\n"); result = -EINVAL; @@ -647,9 +660,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], tuner_i2c, &cnxt_rde250_tunerconfig)) { result = -EINVAL; @@ -660,11 +673,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_SHELBY: case CX231XX_BOARD_CNXT_RDU_250: - dev->dvb->frontend = dvb_attach(s5h1411_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, &xc5000_s5h1411_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1411 front end\n"); result = -EINVAL; @@ -672,9 +685,9 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(xc5000_attach, dev->dvb->frontend, + if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0], tuner_i2c, &cnxt_rdu250_tunerconfig)) { result = -EINVAL; @@ -683,11 +696,11 @@ static int dvb_init(struct cx231xx *dev) break; case CX231XX_BOARD_CNXT_RDE_253S: - dev->dvb->frontend = dvb_attach(s5h1432_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1432_attach, &dvico_s5h1432_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1432 front end\n"); result = -EINVAL; @@ -695,10 +708,10 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, tuner_i2c, + if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], + dev->board.tuner_addr, tuner_i2c, &cnxt_rde253s_tunerconfig)) { result = -EINVAL; goto out_free; @@ -707,11 +720,11 @@ static int dvb_init(struct cx231xx *dev) case CX231XX_BOARD_CNXT_RDU_253S: case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID: - dev->dvb->frontend = dvb_attach(s5h1411_attach, + dev->dvb->frontend[0] = dvb_attach(s5h1411_attach, &tda18271_s5h1411_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach s5h1411 front end\n"); result = -EINVAL; @@ -719,10 +732,10 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - if (!dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, tuner_i2c, + if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0], + dev->board.tuner_addr, tuner_i2c, &cnxt_rde253s_tunerconfig)) { result = -EINVAL; goto out_free; @@ -734,11 +747,11 @@ static int dvb_init(struct cx231xx *dev) "%s: looking for tuner / demod on i2c bus: %d\n", __func__, i2c_adapter_id(tuner_i2c)); - dev->dvb->frontend = dvb_attach(lgdt3305_attach, + dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach, &hcw_lgdt3305_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach LG3305 front end\n"); result = -EINVAL; @@ -746,54 +759,39 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, tuner_i2c, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], + dev->board.tuner_addr, tuner_i2c, &hcw_tda18271_config); break; case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx: { - struct i2c_client *client; - struct i2c_board_info info; - struct si2165_platform_data si2165_pdata; + struct si2165_platform_data si2165_pdata = {}; /* attach demod */ - memset(&si2165_pdata, 0, sizeof(si2165_pdata)); - si2165_pdata.fe = &dev->dvb->frontend; - si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL, - si2165_pdata.ref_freq_Hz = 16000000, - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2165", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2165_pdata; - request_module(info.type); - client = i2c_new_device(demod_i2c, &info); - if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { - dev_err(dev->dev, - "Failed to attach SI2165 front end\n"); - result = -EINVAL; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + si2165_pdata.fe = &dev->dvb->frontend[0]; + si2165_pdata.chip_mode = SI2165_MODE_PLL_XTAL; + si2165_pdata.ref_freq_hz = 16000000; + + /* perform probe/init/attach */ + client = dvb_module_probe("si2165", NULL, demod_i2c, + dev->board.demod_addr, + &si2165_pdata); + if (!client) { result = -ENODEV; goto out_free; } + dvb->i2c_client_demod[0] = client; - dvb->i2c_client_demod = client; - - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, - tuner_i2c, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], + dev->board.tuner_addr, tuner_i2c, &hcw_tda18271_config); dev->cx231xx_reset_analog_tuner = NULL; @@ -801,74 +799,45 @@ static int dvb_init(struct cx231xx *dev) } case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx: { - struct i2c_client *client; - struct i2c_board_info info; - struct si2165_platform_data si2165_pdata; - struct si2157_config si2157_config; + struct si2165_platform_data si2165_pdata = {}; + struct si2157_config si2157_config = {}; /* attach demod */ - memset(&si2165_pdata, 0, sizeof(si2165_pdata)); - si2165_pdata.fe = &dev->dvb->frontend; - si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT, - si2165_pdata.ref_freq_Hz = 24000000, - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, "si2165", I2C_NAME_SIZE); - info.addr = 0x64; - info.platform_data = &si2165_pdata; - request_module(info.type); - client = i2c_new_device(demod_i2c, &info); - if (client == NULL || client->dev.driver == NULL || dev->dvb->frontend == NULL) { - dev_err(dev->dev, - "Failed to attach SI2165 front end\n"); - result = -EINVAL; - goto out_free; - } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + si2165_pdata.fe = &dev->dvb->frontend[0]; + si2165_pdata.chip_mode = SI2165_MODE_PLL_EXT; + si2165_pdata.ref_freq_hz = 24000000; + + /* perform probe/init/attach */ + client = dvb_module_probe("si2165", NULL, demod_i2c, + dev->board.demod_addr, + &si2165_pdata); + if (!client) { result = -ENODEV; goto out_free; } + dvb->i2c_client_demod[0] = client; - dvb->i2c_client_demod = client; - - memset(&info, 0, sizeof(struct i2c_board_info)); - - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif si2157_config.if_port = 1; si2157_config.inversion = true; - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - - client = i2c_new_device( - tuner_i2c, - &info); - if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dev->dvb->frontend); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - dvb_frontend_detach(dev->dvb->frontend); + /* perform probe/init/attach */ + client = dvb_module_probe("si2157", NULL, tuner_i2c, + dev->board.tuner_addr, + &si2157_config); + if (!client) { result = -ENODEV; goto out_free; } - dev->cx231xx_reset_analog_tuner = NULL; dev->dvb->i2c_client_tuner = client; @@ -876,58 +845,44 @@ static int dvb_init(struct cx231xx *dev) } case CX231XX_BOARD_HAUPPAUGE_955Q: { - struct i2c_client *client; - struct i2c_board_info info; - struct si2157_config si2157_config; - - memset(&info, 0, sizeof(struct i2c_board_info)); + struct si2157_config si2157_config = {}; + struct lgdt3306a_config lgdt3306a_config = {}; - dev->dvb->frontend = dvb_attach(lgdt3306a_attach, - &hauppauge_955q_lgdt3306a_config, - demod_i2c - ); + lgdt3306a_config = hauppauge_955q_lgdt3306a_config; + lgdt3306a_config.fe = &dev->dvb->frontend[0]; + lgdt3306a_config.i2c_adapter = &adapter; - if (dev->dvb->frontend == NULL) { - dev_err(dev->dev, - "Failed to attach LGDT3306A frontend.\n"); - result = -EINVAL; + /* perform probe/init/attach */ + client = dvb_module_probe("lgdt3306a", NULL, demod_i2c, + dev->board.demod_addr, + &lgdt3306a_config); + if (!client) { + result = -ENODEV; goto out_free; } + dvb->i2c_client_demod[0] = client; - dev->dvb->frontend->ops.i2c_gate_ctrl = NULL; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; /* attach tuner */ - memset(&si2157_config, 0, sizeof(si2157_config)); - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif si2157_config.if_port = 1; si2157_config.inversion = true; - strlcpy(info.type, "si2157", I2C_NAME_SIZE); - info.addr = 0x60; - info.platform_data = &si2157_config; - request_module("si2157"); - - client = i2c_new_device( - tuner_i2c, - &info); - if (client == NULL || client->dev.driver == NULL) { - dvb_frontend_detach(dev->dvb->frontend); - result = -ENODEV; - goto out_free; - } - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - dvb_frontend_detach(dev->dvb->frontend); + /* perform probe/init/attach */ + client = dvb_module_probe("si2157", NULL, tuner_i2c, + dev->board.tuner_addr, + &si2157_config); + if (!client) { result = -ENODEV; goto out_free; } - dev->cx231xx_reset_analog_tuner = NULL; dev->dvb->i2c_client_tuner = client; @@ -940,11 +895,11 @@ static int dvb_init(struct cx231xx *dev) "%s: looking for demod on i2c bus: %d\n", __func__, i2c_adapter_id(tuner_i2c)); - dev->dvb->frontend = dvb_attach(mb86a20s_attach, + dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach, &pv_mb86a20s_config, demod_i2c); - if (dev->dvb->frontend == NULL) { + if (!dev->dvb->frontend[0]) { dev_err(dev->dev, "Failed to attach mb86a20s demod\n"); result = -EINVAL; @@ -952,10 +907,10 @@ static int dvb_init(struct cx231xx *dev) } /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; - dvb_attach(tda18271_attach, dev->dvb->frontend, - 0x60, tuner_i2c, + dvb_attach(tda18271_attach, dev->dvb->frontend[0], + dev->board.tuner_addr, tuner_i2c, &pv_tda18271_config); break; @@ -963,109 +918,183 @@ static int dvb_init(struct cx231xx *dev) { struct si2157_config si2157_config = {}; struct si2168_config si2168_config = {}; - struct i2c_board_info info = {}; - struct i2c_client *client; - struct i2c_adapter *adapter; /* attach demodulator chip */ si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */ - si2168_config.fe = &dev->dvb->frontend; + si2168_config.fe = &dev->dvb->frontend[0]; si2168_config.i2c_adapter = &adapter; si2168_config.ts_clock_inv = true; - strlcpy(info.type, "si2168", sizeof(info.type)); - info.addr = dev->board.demod_addr; - info.platform_data = &si2168_config; - - request_module(info.type); - client = i2c_new_device(demod_i2c, &info); - - if (client == NULL || client->dev.driver == NULL) { + /* perform probe/init/attach */ + client = dvb_module_probe("si2168", NULL, demod_i2c, + dev->board.demod_addr, + &si2168_config); + if (!client) { result = -ENODEV; goto out_free; } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - result = -ENODEV; - goto out_free; - } - - dvb->i2c_client_demod = client; + dvb->i2c_client_demod[0] = client; /* attach tuner chip */ - si2157_config.fe = dev->dvb->frontend; + si2157_config.fe = dev->dvb->frontend[0]; #ifdef CONFIG_MEDIA_CONTROLLER_DVB si2157_config.mdev = dev->media_dev; #endif si2157_config.if_port = 1; si2157_config.inversion = false; - memset(&info, 0, sizeof(info)); - strlcpy(info.type, "si2157", sizeof(info.type)); - info.addr = dev->board.tuner_addr; - info.platform_data = &si2157_config; - - request_module(info.type); - client = i2c_new_device(tuner_i2c, &info); - - if (client == NULL || client->dev.driver == NULL) { - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); + /* perform probe/init/attach */ + client = dvb_module_probe("si2157", NULL, tuner_i2c, + dev->board.tuner_addr, + &si2157_config); + if (!client) { result = -ENODEV; goto out_free; } - - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); - module_put(dvb->i2c_client_demod->dev.driver->owner); - i2c_unregister_device(dvb->i2c_client_demod); - result = -ENODEV; - goto out_free; - } - dev->cx231xx_reset_analog_tuner = NULL; dev->dvb->i2c_client_tuner = client; break; } case CX231XX_BOARD_ASTROMETA_T2HYBRID: { - struct i2c_client *client; - struct i2c_board_info info = {}; struct mn88473_config mn88473_config = {}; /* attach demodulator chip */ mn88473_config.i2c_wr_max = 16; mn88473_config.xtal = 25000000; - mn88473_config.fe = &dev->dvb->frontend; + mn88473_config.fe = &dev->dvb->frontend[0]; + + /* perform probe/init/attach */ + client = dvb_module_probe("mn88473", NULL, demod_i2c, + dev->board.demod_addr, + &mn88473_config); + if (!client) { + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_demod[0] = client; - strlcpy(info.type, "mn88473", sizeof(info.type)); - info.addr = dev->board.demod_addr; - info.platform_data = &mn88473_config; + /* define general-purpose callback pointer */ + dvb->frontend[0]->callback = cx231xx_tuner_callback; - request_module(info.type); - client = i2c_new_device(demod_i2c, &info); + /* attach tuner chip */ + dvb_attach(r820t_attach, dev->dvb->frontend[0], + tuner_i2c, + &astrometa_t2hybrid_r820t_config); + break; + } + case CX231XX_BOARD_HAUPPAUGE_935C: + { + struct si2157_config si2157_config = {}; + struct si2168_config si2168_config = {}; + + /* attach demodulator chip */ + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.fe = &dev->dvb->frontend[0]; + si2168_config.i2c_adapter = &adapter; + si2168_config.ts_clock_inv = true; - if (client == NULL || client->dev.driver == NULL) { + /* perform probe/init/attach */ + client = dvb_module_probe("si2168", NULL, demod_i2c, + dev->board.demod_addr, + &si2168_config); + if (!client) { result = -ENODEV; goto out_free; } + dvb->i2c_client_demod[0] = client; + dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL; + + /* define general-purpose callback pointer */ + dvb->frontend[0]->callback = cx231xx_tuner_callback; + + /* attach tuner */ + si2157_config.fe = dev->dvb->frontend[0]; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + si2157_config.if_port = 1; + si2157_config.inversion = true; + + /* perform probe/init/attach */ + client = dvb_module_probe("si2157", NULL, tuner_i2c, + dev->board.tuner_addr, + &si2157_config); + if (!client) { + result = -ENODEV; + goto out_free; + } + dev->cx231xx_reset_analog_tuner = NULL; + dev->dvb->i2c_client_tuner = client; + break; + } + case CX231XX_BOARD_HAUPPAUGE_975: + { + struct i2c_adapter *adapter2; + struct si2157_config si2157_config = {}; + struct lgdt3306a_config lgdt3306a_config = {}; + struct si2168_config si2168_config = {}; - if (!try_module_get(client->dev.driver->owner)) { - i2c_unregister_device(client); + /* attach first demodulator chip */ + lgdt3306a_config = hauppauge_955q_lgdt3306a_config; + lgdt3306a_config.fe = &dev->dvb->frontend[0]; + lgdt3306a_config.i2c_adapter = &adapter; + + /* perform probe/init/attach */ + client = dvb_module_probe("lgdt3306a", NULL, demod_i2c, + dev->board.demod_addr, + &lgdt3306a_config); + if (!client) { result = -ENODEV; goto out_free; } + dvb->i2c_client_demod[0] = client; - dvb->i2c_client_demod = client; + /* attach second demodulator chip */ + si2168_config.ts_mode = SI2168_TS_SERIAL; + si2168_config.fe = &dev->dvb->frontend[1]; + si2168_config.i2c_adapter = &adapter2; + si2168_config.ts_clock_inv = true; + + /* perform probe/init/attach */ + client = dvb_module_probe("si2168", NULL, adapter, + dev->board.demod_addr2, + &si2168_config); + if (!client) { + result = -ENODEV; + goto out_free; + } + dvb->i2c_client_demod[1] = client; + dvb->frontend[1]->id = 1; /* define general-purpose callback pointer */ - dvb->frontend->callback = cx231xx_tuner_callback; + dvb->frontend[0]->callback = cx231xx_tuner_callback; + dvb->frontend[1]->callback = cx231xx_tuner_callback; - /* attach tuner chip */ - dvb_attach(r820t_attach, dev->dvb->frontend, - tuner_i2c, - &astrometa_t2hybrid_r820t_config); + /* attach tuner */ + si2157_config.fe = dev->dvb->frontend[0]; +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + si2157_config.mdev = dev->media_dev; +#endif + si2157_config.if_port = 1; + si2157_config.inversion = true; + + /* perform probe/init/attach */ + client = dvb_module_probe("si2157", NULL, adapter, + dev->board.tuner_addr, + &si2157_config); + if (!client) { + result = -ENODEV; + goto out_free; + } + dev->cx231xx_reset_analog_tuner = NULL; + dvb->i2c_client_tuner = client; + + dvb->frontend[1]->tuner_priv = dvb->frontend[0]->tuner_priv; + + memcpy(&dvb->frontend[1]->ops.tuner_ops, + &dvb->frontend[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); break; } default: @@ -1074,7 +1103,7 @@ static int dvb_init(struct cx231xx *dev) dev->name); break; } - if (NULL == dvb->frontend) { + if (!dvb->frontend[0]) { dev_err(dev->dev, "%s/2: frontend initialization failed\n", dev->name); result = -EINVAL; @@ -1096,6 +1125,14 @@ ret: return result; out_free: + /* remove I2C tuner */ + dvb_module_release(dvb->i2c_client_tuner); + dvb->i2c_client_tuner = NULL; + /* remove I2C demod(s) */ + dvb_module_release(dvb->i2c_client_demod[1]); + dvb->i2c_client_demod[1] = NULL; + dvb_module_release(dvb->i2c_client_demod[0]); + dvb->i2c_client_demod[0] = NULL; kfree(dvb); dev->dvb = NULL; goto ret; @@ -1110,6 +1147,7 @@ static int dvb_fini(struct cx231xx *dev) if (dev->dvb) { unregister_dvb(dev->dvb); + kfree(dev->dvb); dev->dvb = NULL; } |
