Commit f410b409 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Mauro Carvalho Chehab

media: em28xx: split up em28xx_dvb_init to reduce stack size

With CONFIG_KASAN, the init function uses a large amount of kernel stack:

drivers/media/usb/em28xx/em28xx-dvb.c: In function 'em28xx_dvb_init.part.4':
drivers/media/usb/em28xx/em28xx-dvb.c:2061:1: error: the frame size of 3232 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]

Using gcc-7 with -fsanitize-address-use-after-scope makes this even worse:

drivers/media/usb/em28xx/em28xx-dvb.c: In function 'em28xx_dvb_init':
drivers/media/usb/em28xx/em28xx-dvb.c:2069:1: error: the frame size of 4280 bytes is larger than 3072 bytes [-Werror=frame-larger-than=]

By splitting out each part of the switch/case statement that has its own local
variables into a separate function, no single one of them uses more than 500 bytes,
and with a noinline_for_stack annotation we can ensure that they are not merged
back together.

[mchehab@s-opensource.com: fix conflict with changeset
 be7fd3c3 ("media: em28xx: Hauppauge DualHD second tuner functionality")]
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Signed-off-by: Mauro Carvalho Chehab <>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent cf68c22f
...@@ -932,7 +932,7 @@ static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = { ...@@ -932,7 +932,7 @@ static struct lgdt3306a_config hauppauge_01595_lgdt3306a_config = {
/* ------------------------------------------------------------------ */ /* ------------------------------------------------------------------ */
static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) static noinline_for_stack int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
{ {
struct dvb_frontend *fe; struct dvb_frontend *fe;
struct xc2028_config cfg; struct xc2028_config cfg;
...@@ -1124,352 +1124,283 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb) ...@@ -1124,352 +1124,283 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
dvb_unregister_adapter(&dvb->adapter); dvb_unregister_adapter(&dvb->adapter);
} }
static int em28xx_dvb_init(struct em28xx *dev) static noinline_for_stack int em28174_dvb_init_pctv_460e(struct em28xx *dev)
{ {
int result = 0, dvb_alt = 0; struct em28xx_dvb *dvb = dev->dvb;
struct em28xx_dvb *dvb; struct i2c_client *client;
struct usb_device *udev; struct i2c_board_info board_info;
struct tda10071_platform_data tda10071_pdata = {};
if (dev->is_audio_only) { struct a8293_platform_data a8293_pdata = {};
/* Shouldn't initialize IR for this interface */ int result;
return 0;
}
if (!dev->board.has_dvb) {
/* This device does not support the extension */
return 0;
}
dev_info(&dev->intf->dev, "Binding DVB extension\n");
dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
if (!dvb)
return -ENOMEM;
dev->dvb = dvb;
dvb->fe[0] = dvb->fe[1] = NULL;
/* pre-allocate DVB usb transfer buffers */
if (dev->dvb_xfer_bulk) {
result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
512,
EM28XX_DVB_BULK_PACKET_MULTIPLIER);
} else {
result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
dev->dvb_max_pkt_size_isoc,
EM28XX_DVB_NUM_ISOC_PACKETS);
}
if (result) {
dev_err(&dev->intf->dev,
"failed to pre-allocate USB transfer buffers for DVB.\n");
kfree(dvb);
dev->dvb = NULL;
return result;
}
mutex_lock(&dev->lock);
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
case EM2874_BOARD_LEADERSHIP_ISDBT:
dvb->fe[0] = dvb_attach(s921_attach,
&sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
break; /* attach demod + tuner combo */
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: tda10071_pdata.clk = 40444000, /* 40.444 MHz */
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: tda10071_pdata.i2c_wr_max = 64,
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: tda10071_pdata.ts_mode = TDA10071_TS_SERIAL,
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: tda10071_pdata.pll_multiplier = 20,
dvb->fe[0] = dvb_attach(lgdt330x_attach, tda10071_pdata.tuner_i2c_addr = 0x14,
&em2880_lgdt3303_dev, memset(&board_info, 0, sizeof(board_info));
&dev->i2c_adap[dev->def_i2c_bus]); strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE);
if (em28xx_attach_xc3028(0x61, dev) < 0) { board_info.addr = 0x55;
result = -EINVAL; board_info.platform_data = &tda10071_pdata;
goto out_free; request_module("tda10071");
} client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
break; if (client == NULL || client->dev.driver == NULL) {
case EM2880_BOARD_KWORLD_DVB_310U: result = -ENODEV;
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_with_xc3028,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free; goto out_free;
} }
break; if (!try_module_get(client->dev.driver->owner)) {
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: i2c_unregister_device(client);
case EM2882_BOARD_TERRATEC_HYBRID_XS: result = -ENODEV;
case EM2880_BOARD_EMPIRE_DUAL_TV:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free; goto out_free;
} }
break; dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client);
case EM2880_BOARD_TERRATEC_HYBRID_XS: dvb->i2c_client_demod = client;
case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
case EM2882_BOARD_DIKOM_DK300:
case EM2882_BOARD_KWORLD_VS_DVBT:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
dvb->fe[0] = dvb_attach(mt352_attach,
&terratec_xs_mt352_cfg,
&dev->i2c_adap[dev->def_i2c_bus]);
}
if (em28xx_attach_xc3028(0x61, dev) < 0) { /* attach SEC */
result = -EINVAL; a8293_pdata.dvb_frontend = dvb->fe[0];
goto out_free; memset(&board_info, 0, sizeof(board_info));
} strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
break; board_info.addr = 0x08;
case EM2870_BOARD_TERRATEC_XS_MT2060: board_info.platform_data = &a8293_pdata;
dvb->fe[0] = dvb_attach(zl10353_attach, request_module("a8293");
&em28xx_zl10353_no_i2c_gate_dev, client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
&dev->i2c_adap[dev->def_i2c_bus]); if (client == NULL || client->dev.driver == NULL) {
if (dvb->fe[0] != NULL) { module_put(dvb->i2c_client_demod->dev.driver->owner);
dvb_attach(mt2060_attach, dvb->fe[0], i2c_unregister_device(dvb->i2c_client_demod);
&dev->i2c_adap[dev->def_i2c_bus], result = -ENODEV;
&em28xx_mt2060_config, 1220);
}
break;
case EM2870_BOARD_KWORLD_355U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_no_i2c_gate_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(qt1010_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config);
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
dvb->fe[0] = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free; goto out_free;
} }
break; if (!try_module_get(client->dev.driver->owner)) {
case EM2882_BOARD_KWORLD_ATSC_315U: i2c_unregister_device(client);
dvb->fe[0] = dvb_attach(lgdt330x_attach, module_put(dvb->i2c_client_demod->dev.driver->owner);
&em2880_lgdt3303_dev, i2c_unregister_device(dvb->i2c_client_demod);
&dev->i2c_adap[dev->def_i2c_bus]); result = -ENODEV;
if (dvb->fe[0] != NULL) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free; goto out_free;
} }
} dvb->i2c_client_sec = client;
break; result = 0;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: out_free:
case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: return result;
dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, }
&dev->i2c_adap[dev->def_i2c_bus],
&dev->intf->dev); static noinline_for_stack int em28178_dvb_init_pctv_461e(struct em28xx *dev)
if (em28xx_attach_xc3028(0x61, dev) < 0) { {
result = -EINVAL; struct em28xx_dvb *dvb = dev->dvb;
struct i2c_client *client;
struct i2c_adapter *i2c_adapter;
struct i2c_board_info board_info;
struct m88ds3103_platform_data m88ds3103_pdata = {};
struct ts2020_config ts2020_config = {};
struct a8293_platform_data a8293_pdata = {};
int result;
/* attach demod */
m88ds3103_pdata.clk = 27000000;
m88ds3103_pdata.i2c_wr_max = 33;
m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL;
m88ds3103_pdata.ts_clk = 16000;
m88ds3103_pdata.ts_clk_pol = 1;
m88ds3103_pdata.agc = 0x99;
memset(&board_info, 0, sizeof(board_info));
strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
board_info.addr = 0x68;
board_info.platform_data = &m88ds3103_pdata;
request_module("m88ds3103");
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
break; if (!try_module_get(client->dev.driver->owner)) {
case EM2870_BOARD_REDDO_DVB_C_USB_BOX: i2c_unregister_device(client);
/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */ result = -ENODEV;
dvb->fe[0] = dvb_attach(tda10023_attach,
&em28xx_tda10023_config,
&dev->i2c_adap[dev->def_i2c_bus], 0x48);
if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
0x60, TUNER_PHILIPS_CU1216L)) {
result = -EINVAL;
goto out_free; goto out_free;
} }
} dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client);
break; i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
case EM2870_BOARD_KWORLD_A340: dvb->i2c_client_demod = client;
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev, /* attach tuner */
&dev->i2c_adap[dev->def_i2c_bus]); ts2020_config.fe = dvb->fe[0];
if (!dvb->fe[0]) { memset(&board_info, 0, sizeof(board_info));
result = -EINVAL; strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE);
board_info.addr = 0x60;
board_info.platform_data = &ts2020_config;
request_module("ts2020");
client = i2c_new_device(i2c_adapter, &board_info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, if (!try_module_get(client->dev.driver->owner)) {
&dev->i2c_adap[dev->def_i2c_bus], i2c_unregister_device(client);
&kworld_a340_config)) { module_put(dvb->i2c_client_demod->dev.driver->owner);
dvb_frontend_detach(dvb->fe[0]); i2c_unregister_device(dvb->i2c_client_demod);
result = -EINVAL; result = -ENODEV;
goto out_free; goto out_free;
} }
break; dvb->i2c_client_tuner = client;
case EM28174_BOARD_PCTV_290E: /* delegate signal strength measurement to tuner */
/* set default GPIO0 for LNA, used if GPIOLIB is undefined */ dvb->fe[0]->ops.read_signal_strength =
dvb->lna_gpio = CXD2820R_GPIO_E | CXD2820R_GPIO_O | dvb->fe[0]->ops.tuner_ops.get_rf_strength;
CXD2820R_GPIO_L;
dvb->fe[0] = dvb_attach(cxd2820r_attach,
&em28xx_cxd2820r_config,
&dev->i2c_adap[dev->def_i2c_bus],
&dvb->lna_gpio);
if (dvb->fe[0]) {
/* FE 0 attach tuner */
if (!dvb_attach(tda18271_attach,
dvb->fe[0],
0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]); /* attach SEC */
result = -EINVAL; a8293_pdata.dvb_frontend = dvb->fe[0];
memset(&board_info, 0, sizeof(board_info));
strlcpy(board_info.type, "a8293", I2C_NAME_SIZE);
board_info.addr = 0x08;
board_info.platform_data = &a8293_pdata;
request_module("a8293");
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_tuner->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_tuner);
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) {
#ifdef CONFIG_GPIOLIB i2c_unregister_device(client);
/* enable LNA for DVB-T, DVB-T2 and DVB-C */ module_put(dvb->i2c_client_tuner->dev.driver->owner);
result = gpio_request_one(dvb->lna_gpio, i2c_unregister_device(dvb->i2c_client_tuner);
GPIOF_OUT_INIT_LOW, NULL); module_put(dvb->i2c_client_demod->dev.driver->owner);
if (result) i2c_unregister_device(dvb->i2c_client_demod);
dev_err(&dev->intf->dev, result = -ENODEV;
"gpio request failed %d\n", goto out_free;
result);
else
gpio_free(dvb->lna_gpio);
result = 0; /* continue even set LNA fails */
#endif
dvb->fe[0]->ops.set_lna = em28xx_pctv_290e_set_lna;
} }
dvb->i2c_client_sec = client;
result = 0;
out_free:
return result;
}
break; static noinline_for_stack int em28178_dvb_init_pctv_292e(struct em28xx *dev)
case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: {
{ struct em28xx_dvb *dvb = dev->dvb;
struct xc5000_config cfg; struct i2c_adapter *adapter;
struct i2c_client *client;
hauppauge_hvr930c_init(dev); struct i2c_board_info info;
struct si2168_config si2168_config;
struct si2157_config si2157_config;
int result;
dvb->fe[0] = dvb_attach(drxk_attach, /* attach demod */
&hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]); memset(&si2168_config, 0, sizeof(si2168_config));
if (!dvb->fe[0]) { si2168_config.i2c_adapter = &adapter;
result = -EINVAL; si2168_config.fe = &dvb->fe[0];
si2168_config.ts_mode = SI2168_TS_PARALLEL;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
/* FIXME: do we need a pll semaphore? */
dvb->fe[0]->sec_priv = dvb;
sema_init(&dvb->pll_mutex, 1);
dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
/* Attach xc5000 */ if (!try_module_get(client->dev.driver->owner)) {
memset(&cfg, 0, sizeof(cfg)); i2c_unregister_device(client);
cfg.i2c_address = 0x61; result = -ENODEV;
cfg.if_khz = 4000;
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
&cfg)) {
result = -EINVAL;
goto out_free; goto out_free;
} }
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
break; dvb->i2c_client_demod = client;
}
case EM2884_BOARD_TERRATEC_H5:
terratec_h5_init(dev);
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]); /* attach tuner */
if (!dvb->fe[0]) { memset(&si2157_config, 0, sizeof(si2157_config));
result = -EINVAL; si2157_config.fe = dvb->fe[0];
si2157_config.if_port = 1;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
/* FIXME: do we need a pll semaphore? */
dvb->fe[0]->sec_priv = dvb;
sema_init(&dvb->pll_mutex, 1);
dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
/* Attach tda18271 to DVB-C frontend */ if (!try_module_get(client->dev.driver->owner)) {
if (dvb->fe[0]->ops.i2c_gate_ctrl) i2c_unregister_device(client);
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1); module_put(dvb->i2c_client_demod->dev.driver->owner);
if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) { i2c_unregister_device(dvb->i2c_client_demod);
result = -EINVAL; result = -ENODEV;
goto out_free; goto out_free;
} }
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0); dvb->i2c_client_tuner = client;
dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
break; result = 0;
case EM2884_BOARD_C3TECH_DIGITAL_DUO: out_free:
dvb->fe[0] = dvb_attach(mb86a20s_attach, return result;
&c3tech_duo_mb86a20s_config, }
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) static noinline_for_stack int em28178_dvb_init_terratec_t2_stick_hd(struct em28xx *dev)
dvb_attach(tda18271_attach, dvb->fe[0], 0x60, {
&dev->i2c_adap[dev->def_i2c_bus], struct em28xx_dvb *dvb = dev->dvb;
&c3tech_duo_tda18271_config); struct i2c_adapter *adapter;
break;
case EM28174_BOARD_PCTV_460E: {
struct i2c_client *client; struct i2c_client *client;
struct i2c_board_info board_info; struct i2c_board_info info;
struct tda10071_platform_data tda10071_pdata = {}; struct si2168_config si2168_config;
struct a8293_platform_data a8293_pdata = {}; struct si2157_config si2157_config;
int result;
/* attach demod + tuner combo */ /* attach demod */
tda10071_pdata.clk = 40444000, /* 40.444 MHz */ memset(&si2168_config, 0, sizeof(si2168_config));
tda10071_pdata.i2c_wr_max = 64, si2168_config.i2c_adapter = &adapter;
tda10071_pdata.ts_mode = TDA10071_TS_SERIAL, si2168_config.fe = &dvb->fe[0];
tda10071_pdata.pll_multiplier = 20, si2168_config.ts_mode = SI2168_TS_PARALLEL;
tda10071_pdata.tuner_i2c_addr = 0x14, memset(&info, 0, sizeof(struct i2c_board_info));
memset(&board_info, 0, sizeof(board_info)); strlcpy(info.type, "si2168", I2C_NAME_SIZE);
strlcpy(board_info.type, "tda10071_cx24118", I2C_NAME_SIZE); info.addr = 0x64;
board_info.addr = 0x55; info.platform_data = &si2168_config;
board_info.platform_data = &tda10071_pdata; request_module(info.type);
request_module("tda10071"); client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info);
if (client == NULL || client->dev.driver == NULL) { if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client); i2c_unregister_device(client);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->fe[0] = tda10071_pdata.get_dvb_frontend(client);
dvb->i2c_client_demod = client; dvb->i2c_client_demod = client;
/* attach SEC */ /* attach tuner */
a8293_pdata.dvb_frontend = dvb->fe[0]; memset(&si2157_config, 0, sizeof(si2157_config));
memset(&board_info, 0, sizeof(board_info)); si2157_config.fe = dvb->fe[0];
strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); si2157_config.if_port = 0;
board_info.addr = 0x08; #ifdef CONFIG_MEDIA_CONTROLLER_DVB
board_info.platform_data = &a8293_pdata; si2157_config.mdev = dev->media_dev;
request_module("a8293"); #endif
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2146", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("si2157");
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) { if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner); module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod); i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client); i2c_unregister_device(client);
module_put(dvb->i2c_client_demod->dev.driver->owner); module_put(dvb->i2c_client_demod->dev.driver->owner);
...@@ -1477,197 +1408,201 @@ static int em28xx_dvb_init(struct em28xx *dev) ...@@ -1477,197 +1408,201 @@ static int em28xx_dvb_init(struct em28xx *dev)
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_sec = client;
break;
}
case EM2874_BOARD_DELOCK_61959:
case EM2874_BOARD_MAXMEDIA_UB425_TC:
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* disable I2C-gate */
dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
/* attach tuner */ dvb->i2c_client_tuner = client;
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, result = 0;
&dev->i2c_adap[dev->def_i2c_bus], out_free:
&em28xx_cxd2820r_tda18271_config)) { return result;
dvb_frontend_detach(dvb->fe[0]); }
result = -EINVAL;
goto out_free;
}
}
break;
case EM2884_BOARD_PCTV_510E:
case EM2884_BOARD_PCTV_520E:
pctv_520e_init(dev);
/* attach demodulator */ static noinline_for_stack int em28178_dvb_init_plex_px_bcud(struct em28xx *dev)
dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk, {
&dev->i2c_adap[dev->def_i2c_bus]); struct em28xx_dvb *dvb = dev->dvb;
struct i2c_client *client;
struct i2c_board_info info;
struct tc90522_config tc90522_config;
struct qm1d1c0042_config qm1d1c0042_config;
int result;
if (dvb->fe[0]) { /* attach demod */
/* attach tuner */ memset(&tc90522_config, 0, sizeof(tc90522_config));
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, memset(&info, 0, sizeof(struct i2c_board_info));
&dev->i2c_adap[dev->def_i2c_bus], strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE);
&em28xx_cxd2820r_tda18271_config)) { info.addr = 0x15;
dvb_frontend_detach(dvb->fe[0]); info.platform_data = &tc90522_config;
result = -EINVAL; request_module("tc90522");
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
} dvb->i2c_client_demod = client;
break; if (!try_module_get(client->dev.driver->owner)) {
case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008: i2c_unregister_device(client);
case EM2884_BOARD_CINERGY_HTC_STICK: result = -ENODEV;
case EM2884_BOARD_TERRATEC_H6:
terratec_htc_stick_init(dev);
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
&dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
/* Attach the demodulator. */ /* attach tuner */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, memset(&qm1d1c0042_config, 0,
&dev->i2c_adap[dev->def_i2c_bus], sizeof(qm1d1c0042_config));
&em28xx_cxd2820r_tda18271_config)) { qm1d1c0042_config.fe = tc90522_config.fe;
result = -EINVAL; qm1d1c0042_config.lpf = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
info.addr = 0x61;
info.platform_data = &qm1d1c0042_config;
request_module(info.type);
client = i2c_new_device(tc90522_config.tuner_i2c,
&info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
break; dvb->i2c_client_tuner = client;
case EM2884_BOARD_TERRATEC_HTC_USB_XS: if (!try_module_get(client->dev.driver->owner)) {
terratec_htc_usb_xs_init(dev); i2c_unregister_device(client);
module_put(dvb->i2c_client_demod->dev.driver->owner);
/* attach demodulator */ i2c_unregister_device(dvb->i2c_client_demod);
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk, result = -ENODEV;
&dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
dvb->fe[0] = tc90522_config.fe;
px_bcud_init(dev);
result = 0;
out_free:
return result;
}
/* Attach the demodulator. */ static noinline_for_stack int em28174_dvb_init_hauppauge_wintv_dualhd_dvb(struct em28xx *dev)
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, {
&dev->i2c_adap[dev->def_i2c_bus], struct em28xx_dvb *dvb = dev->dvb;
&em28xx_cxd2820r_tda18271_config)) { struct i2c_adapter *adapter;
result = -EINVAL; struct i2c_client *client;
goto out_free; struct i2c_board_info info;
} struct si2168_config si2168_config;
break; struct si2157_config si2157_config;
case EM2874_BOARD_KWORLD_UB435Q_V2: int result;
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2874_lgdt3305_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
/* Attach the demodulator. */ /* attach demod */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, memset(&si2168_config, 0, sizeof(si2168_config));
&dev->i2c_adap[dev->def_i2c_bus], si2168_config.i2c_adapter = &adapter;
&kworld_ub435q_v2_config)) { si2168_config.fe = &dvb->fe[0];
result = -EINVAL; si2168_config.ts_mode = SI2168_TS_SERIAL;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
if (dev->ts == PRIMARY_TS)
info.addr = 0x64;
else
info.addr = 0x67;
info.platform_data = &si2168_config;
request_module(info.type);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
break;
case EM2874_BOARD_KWORLD_UB435Q_V3:
{
struct i2c_client *client;
struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
struct i2c_board_info board_info = {
.type = "tda18212",
.addr = 0x60,
.platform_data = &kworld_ub435q_v3_config,
};
dvb->fe[0] = dvb_attach(lgdt3305_attach, if (!try_module_get(client->dev.driver->owner)) {
&em2874_lgdt3305_nogate_dev, i2c_unregister_device(client);
&dev->i2c_adap[dev->def_i2c_bus]); result = -ENODEV;
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
dvb->i2c_client_demod = client;
/* attach tuner */ /* attach tuner */
kworld_ub435q_v3_config.fe = dvb->fe[0]; memset(&si2157_config, 0, sizeof(si2157_config));
request_module("tda18212"); si2157_config.fe = dvb->fe[0];
client = i2c_new_device(adapter, &board_info); si2157_config.if_port = 1;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
if (dev->ts == PRIMARY_TS)
info.addr = 0x60;
else
info.addr = 0x63;
info.platform_data = &si2157_config;
request_module(info.type);
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) { if (client == NULL || client->dev.driver == NULL) {
dvb_frontend_detach(dvb->fe[0]); module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client); i2c_unregister_device(client);
dvb_frontend_detach(dvb->fe[0]); module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_tuner = client; dvb->i2c_client_tuner = client;
break; result = 0;
} out_free:
case EM2874_BOARD_PCTV_HD_MINI_80E: return result;
dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]); }
if (dvb->fe[0] != NULL) {
dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60, static int em28174_dvb_init_hauppauge_wintv_dualhd_01595(struct em28xx *dev)
&dev->i2c_adap[dev->def_i2c_bus], {
&pinnacle_80e_dvb_config); struct em28xx_dvb *dvb = dev->dvb;
if (!dvb->fe[0]) { struct i2c_adapter *adapter;
result = -EINVAL;
goto out_free;
}
}
break;
case EM28178_BOARD_PCTV_461E: {
struct i2c_client *client; struct i2c_client *client;
struct i2c_adapter *i2c_adapter; struct i2c_board_info info = {};
struct i2c_board_info board_info; struct lgdt3306a_config lgdt3306a_config;
struct m88ds3103_platform_data m88ds3103_pdata = {}; struct si2157_config si2157_config = {};
struct ts2020_config ts2020_config = {}; int result;
struct a8293_platform_data a8293_pdata = {};
/* attach demod */ /* attach demod */
m88ds3103_pdata.clk = 27000000; lgdt3306a_config = hauppauge_01595_lgdt3306a_config;
m88ds3103_pdata.i2c_wr_max = 33; lgdt3306a_config.fe = &dvb->fe[0];
m88ds3103_pdata.ts_mode = M88DS3103_TS_PARALLEL; lgdt3306a_config.i2c_adapter = &adapter;
m88ds3103_pdata.ts_clk = 16000; strlcpy(info.type, "lgdt3306a", sizeof(info.type));
m88ds3103_pdata.ts_clk_pol = 1; if (dev->ts == PRIMARY_TS)
m88ds3103_pdata.agc = 0x99; info.addr = 0x59;
memset(&board_info, 0, sizeof(board_info)); else
strlcpy(board_info.type, "m88ds3103", I2C_NAME_SIZE); info.addr = 0x0e;
board_info.addr = 0x68; info.platform_data = &lgdt3306a_config;
board_info.platform_data = &m88ds3103_pdata; request_module(info.type);
request_module("m88ds3103"); client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); &info);
if (client == NULL || client->dev.driver == NULL) { if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client); i2c_unregister_device(client);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->fe[0] = m88ds3103_pdata.get_dvb_frontend(client);
i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
dvb->i2c_client_demod = client; dvb->i2c_client_demod = client;
/* attach tuner */ /* attach tuner */
ts2020_config.fe = dvb->fe[0]; si2157_config.fe = dvb->fe[0];
memset(&board_info, 0, sizeof(board_info)); si2157_config.if_port = 1;
strlcpy(board_info.type, "ts2022", I2C_NAME_SIZE); si2157_config.inversion = 1;
board_info.addr = 0x60; #ifdef CONFIG_MEDIA_CONTROLLER_DVB
board_info.platform_data = &ts2020_config; si2157_config.mdev = dev->media_dev;
request_module("ts2020"); #endif
client = i2c_new_device(i2c_adapter, &board_info); memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", sizeof(info.type));
if (dev->ts == PRIMARY_TS)
info.addr = 0x60;
else
info.addr = 0x62;
info.platform_data = &si2157_config;
request_module(info.type);
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) { if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner); module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod); i2c_unregister_device(dvb->i2c_client_demod);
...@@ -1681,360 +1616,494 @@ static int em28xx_dvb_init(struct em28xx *dev) ...@@ -1681,360 +1616,494 @@ static int em28xx_dvb_init(struct em28xx *dev)
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_tuner = client; dvb->i2c_client_tuner = client;
/* delegate signal strength measurement to tuner */ result = 0;
dvb->fe[0]->ops.read_signal_strength = out_free:
dvb->fe[0]->ops.tuner_ops.get_rf_strength; return result;
}
static int em28xx_dvb_init(struct em28xx *dev)
{
int result = 0, dvb_alt = 0;
struct em28xx_dvb *dvb;
struct usb_device *udev;
/* attach SEC */ if (dev->is_audio_only) {
a8293_pdata.dvb_frontend = dvb->fe[0]; /* Shouldn't initialize IR for this interface */
memset(&board_info, 0, sizeof(board_info)); return 0;
strlcpy(board_info.type, "a8293", I2C_NAME_SIZE); }
board_info.addr = 0x08;
board_info.platform_data = &a8293_pdata; if (!dev->board.has_dvb) {
request_module("a8293"); /* This device does not support the extension */
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &board_info); return 0;
if (client == NULL || client->dev.driver == NULL) { }
module_put(dvb->i2c_client_tuner->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_tuner); dev_info(&dev->intf->dev, "Binding DVB extension\n");
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod); dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
result = -ENODEV; if (!dvb)
return -ENOMEM;
dev->dvb = dvb;
dvb->fe[0] = dvb->fe[1] = NULL;
/* pre-allocate DVB usb transfer buffers */
if (dev->dvb_xfer_bulk) {
result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
512,
EM28XX_DVB_BULK_PACKET_MULTIPLIER);
} else {
result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
dev->dvb_xfer_bulk,
EM28XX_DVB_NUM_BUFS,
dev->dvb_max_pkt_size_isoc,
EM28XX_DVB_NUM_ISOC_PACKETS);
}
if (result) {
dev_err(&dev->intf->dev,
"failed to pre-allocate USB transfer buffers for DVB.\n");
kfree(dvb);
dev->dvb = NULL;
return result;
}
mutex_lock(&dev->lock);
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
case EM2874_BOARD_LEADERSHIP_ISDBT:
dvb->fe[0] = dvb_attach(s921_attach,
&sharp_isdbt, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
}
break;
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
case EM2880_BOARD_KWORLD_DVB_310U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_with_xc3028,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
case EM2882_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_EMPIRE_DUAL_TV:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
case EM2880_BOARD_TERRATEC_HYBRID_XS:
case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
case EM2882_BOARD_DIKOM_DK300:
case EM2882_BOARD_KWORLD_VS_DVBT:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_xc3028_no_i2c_gate,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] == NULL) {
/* This board could have either a zl10353 or a mt352.
If the chip id isn't for zl10353, try mt352 */
dvb->fe[0] = dvb_attach(mt352_attach,
&terratec_xs_mt352_cfg,
&dev->i2c_adap[dev->def_i2c_bus]);
}
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
case EM2870_BOARD_TERRATEC_XS_MT2060:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_no_i2c_gate_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) {
dvb_attach(mt2060_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
&em28xx_mt2060_config, 1220);
}
break;
case EM2870_BOARD_KWORLD_355U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_no_i2c_gate_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(qt1010_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus], &em28xx_qt1010_config);
break;
case EM2883_BOARD_KWORLD_HYBRID_330U:
case EM2882_BOARD_EVGA_INDTUBE:
dvb->fe[0] = dvb_attach(s5h1409_attach,
&em28xx_s5h1409_with_xc3028,
&dev->i2c_adap[dev->def_i2c_bus]);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
}
break;
case EM2882_BOARD_KWORLD_ATSC_315U:
dvb->fe[0] = dvb_attach(lgdt330x_attach,
&em2880_lgdt3303_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
&dev->i2c_adap[dev->def_i2c_bus],
0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
module_put(dvb->i2c_client_tuner->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_tuner);
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free;
} }
dvb->i2c_client_sec = client;
break; break;
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL,
&dev->i2c_adap[dev->def_i2c_bus],
&dev->intf->dev);
if (em28xx_attach_xc3028(0x61, dev) < 0) {
result = -EINVAL;
goto out_free;
} }
case EM28178_BOARD_PCTV_292E: break;
{ case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
struct i2c_adapter *adapter; /* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
struct i2c_client *client; dvb->fe[0] = dvb_attach(tda10023_attach,
struct i2c_board_info info; &em28xx_tda10023_config,
struct si2168_config si2168_config; &dev->i2c_adap[dev->def_i2c_bus], 0x48);
struct si2157_config si2157_config; if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
/* attach demod */ &dev->i2c_adap[dev->def_i2c_bus],
memset(&si2168_config, 0, sizeof(si2168_config)); 0x60, TUNER_PHILIPS_CU1216L)) {
si2168_config.i2c_adapter = &adapter; result = -EINVAL;
si2168_config.fe = &dvb->fe[0];
si2168_config.ts_mode = SI2168_TS_PARALLEL;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
}
if (!try_module_get(client->dev.driver->owner)) { break;
i2c_unregister_device(client); case EM2870_BOARD_KWORLD_A340:
result = -ENODEV; dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
dvb->i2c_client_demod = client; &dev->i2c_adap[dev->def_i2c_bus],
&kworld_a340_config)) {
/* attach tuner */ dvb_frontend_detach(dvb->fe[0]);
memset(&si2157_config, 0, sizeof(si2157_config)); result = -EINVAL;
si2157_config.fe = dvb->fe[0];
si2157_config.if_port = 1;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module(info.type);
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
break;
case EM28174_BOARD_PCTV_290E:
/* set default GPIO0 for LNA, used if GPIOLIB is undefined */
dvb->lna_gpio = CXD2820R_GPIO_E | CXD2820R_GPIO_O |
CXD2820R_GPIO_L;
dvb->fe[0] = dvb_attach(cxd2820r_attach,
&em28xx_cxd2820r_config,
&dev->i2c_adap[dev->def_i2c_bus],
&dvb->lna_gpio);
if (dvb->fe[0]) {
/* FE 0 attach tuner */
if (!dvb_attach(tda18271_attach,
dvb->fe[0],
0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
if (!try_module_get(client->dev.driver->owner)) { dvb_frontend_detach(dvb->fe[0]);
i2c_unregister_device(client); result = -EINVAL;
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_tuner = client; #ifdef CONFIG_GPIOLIB
dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna; /* enable LNA for DVB-T, DVB-T2 and DVB-C */
result = gpio_request_one(dvb->lna_gpio,
GPIOF_OUT_INIT_LOW, NULL);
if (result)
dev_err(&dev->intf->dev,
"gpio request failed %d\n",
result);
else
gpio_free(dvb->lna_gpio);
result = 0; /* continue even set LNA fails */
#endif
dvb->fe[0]->ops.set_lna = em28xx_pctv_290e_set_lna;
} }
break; break;
case EM28178_BOARD_TERRATEC_T2_STICK_HD: case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
{ {
struct i2c_adapter *adapter; struct xc5000_config cfg;
struct i2c_client *client;
struct i2c_board_info info;
struct si2168_config si2168_config;
struct si2157_config si2157_config;
/* attach demod */ hauppauge_hvr930c_init(dev);
memset(&si2168_config, 0, sizeof(si2168_config));
si2168_config.i2c_adapter = &adapter;
si2168_config.fe = &dvb->fe[0];
si2168_config.ts_mode = SI2168_TS_PARALLEL;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
info.platform_data = &si2168_config;
request_module(info.type);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free;
}
if (!try_module_get(client->dev.driver->owner)) { dvb->fe[0] = dvb_attach(drxk_attach,
i2c_unregister_device(client); &hauppauge_930c_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
result = -ENODEV; if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
/* FIXME: do we need a pll semaphore? */
dvb->fe[0]->sec_priv = dvb;
sema_init(&dvb->pll_mutex, 1);
dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
dvb->i2c_client_demod = client; /* Attach xc5000 */
memset(&cfg, 0, sizeof(cfg));
cfg.i2c_address = 0x61;
cfg.if_khz = 4000;
/* attach tuner */ if (dvb->fe[0]->ops.i2c_gate_ctrl)
memset(&si2157_config, 0, sizeof(si2157_config)); dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
si2157_config.fe = dvb->fe[0]; if (!dvb_attach(xc5000_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
si2157_config.if_port = 0; &cfg)) {
#ifdef CONFIG_MEDIA_CONTROLLER_DVB result = -EINVAL;
si2157_config.mdev = dev->media_dev;
#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2146", I2C_NAME_SIZE);
info.addr = 0x60;
info.platform_data = &si2157_config;
request_module("si2157");
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
if (dvb->fe[0]->ops.i2c_gate_ctrl)
dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
if (!try_module_get(client->dev.driver->owner)) { break;
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;
} }
case EM2884_BOARD_TERRATEC_H5:
terratec_h5_init(dev);
dvb->i2c_client_tuner = client; dvb->fe[0] = dvb_attach(drxk_attach, &terratec_h5_drxk, &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
} }
break; /* FIXME: do we need a pll semaphore? */
dvb->fe[0]->sec_priv = dvb;
case EM28178_BOARD_PLEX_PX_BCUD: sema_init(&dvb->pll_mutex, 1);
{ dvb->gate_ctrl = dvb->fe[0]->ops.i2c_gate_ctrl;
struct i2c_client *client; dvb->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
struct i2c_board_info info;
struct tc90522_config tc90522_config;
struct qm1d1c0042_config qm1d1c0042_config;
/* attach demod */ /* Attach tda18271 to DVB-C frontend */
memset(&tc90522_config, 0, sizeof(tc90522_config)); if (dvb->fe[0]->ops.i2c_gate_ctrl)
memset(&info, 0, sizeof(struct i2c_board_info)); dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
strlcpy(info.type, "tc90522sat", I2C_NAME_SIZE); if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
info.addr = 0x15; result = -EINVAL;
info.platform_data = &tc90522_config;
request_module("tc90522");
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_demod = client; if (dvb->fe[0]->ops.i2c_gate_ctrl)
if (!try_module_get(client->dev.driver->owner)) { dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);
i2c_unregister_device(client);
result = -ENODEV; break;
case EM2884_BOARD_C3TECH_DIGITAL_DUO:
dvb->fe[0] = dvb_attach(mb86a20s_attach,
&c3tech_duo_mb86a20s_config,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL)
dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&c3tech_duo_tda18271_config);
break;
case EM28174_BOARD_PCTV_460E:
result = em28174_dvb_init_pctv_460e(dev);
if (result)
goto out_free; goto out_free;
} break;
case EM2874_BOARD_DELOCK_61959:
case EM2874_BOARD_MAXMEDIA_UB425_TC:
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &maxmedia_ub425_tc_drxk,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* disable I2C-gate */
dvb->fe[0]->ops.i2c_gate_ctrl = NULL;
/* attach tuner */ /* attach tuner */
memset(&qm1d1c0042_config, 0, if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
sizeof(qm1d1c0042_config)); &dev->i2c_adap[dev->def_i2c_bus],
qm1d1c0042_config.fe = tc90522_config.fe; &em28xx_cxd2820r_tda18271_config)) {
qm1d1c0042_config.lpf = 1; dvb_frontend_detach(dvb->fe[0]);
memset(&info, 0, sizeof(struct i2c_board_info)); result = -EINVAL;
strlcpy(info.type, "qm1d1c0042", I2C_NAME_SIZE);
info.addr = 0x61;
info.platform_data = &qm1d1c0042_config;
request_module(info.type);
client = i2c_new_device(tc90522_config.tuner_i2c,
&info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_tuner = client; }
if (!try_module_get(client->dev.driver->owner)) { break;
i2c_unregister_device(client); case EM2884_BOARD_PCTV_510E:
module_put(dvb->i2c_client_demod->dev.driver->owner); case EM2884_BOARD_PCTV_520E:
i2c_unregister_device(dvb->i2c_client_demod); pctv_520e_init(dev);
result = -ENODEV;
/* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &pctv_520e_drxk,
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0]) {
/* attach tuner */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
goto out_free; goto out_free;
} }
dvb->fe[0] = tc90522_config.fe;
px_bcud_init(dev);
} }
break; break;
case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB: case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008:
{ case EM2884_BOARD_CINERGY_HTC_STICK:
struct i2c_adapter *adapter; case EM2884_BOARD_TERRATEC_H6:
struct i2c_client *client; terratec_htc_stick_init(dev);
struct i2c_board_info info;
struct si2168_config si2168_config;
struct si2157_config si2157_config;
/* attach demod */ /* attach demodulator */
memset(&si2168_config, 0, sizeof(si2168_config)); dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
si2168_config.i2c_adapter = &adapter; &dev->i2c_adap[dev->def_i2c_bus]);
si2168_config.fe = &dvb->fe[0]; if (!dvb->fe[0]) {
si2168_config.ts_mode = SI2168_TS_SERIAL; result = -EINVAL;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
if (dev->ts == PRIMARY_TS)
info.addr = 0x64;
else
info.addr = 0x67;
info.platform_data = &si2168_config;
request_module(info.type);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { /* Attach the demodulator. */
i2c_unregister_device(client); if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
result = -ENODEV; &dev->i2c_adap[dev->def_i2c_bus],
&em28xx_cxd2820r_tda18271_config)) {
result = -EINVAL;
goto out_free; goto out_free;
} }
break;
case EM2884_BOARD_TERRATEC_HTC_USB_XS:
terratec_htc_usb_xs_init(dev);
dvb->i2c_client_demod = client; /* attach demodulator */
dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk,
/* attach tuner */ &dev->i2c_adap[dev->def_i2c_bus]);
memset(&si2157_config, 0, sizeof(si2157_config)); if (!dvb->fe[0]) {
si2157_config.fe = dvb->fe[0]; result = -EINVAL;
si2157_config.if_port = 1;
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
if (dev->ts == PRIMARY_TS)
info.addr = 0x60;
else
info.addr = 0x63;
info.platform_data = &si2157_config;
request_module(info.type);
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { /* Attach the demodulator. */
i2c_unregister_device(client); if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
module_put(dvb->i2c_client_demod->dev.driver->owner); &dev->i2c_adap[dev->def_i2c_bus],
i2c_unregister_device(dvb->i2c_client_demod); &em28xx_cxd2820r_tda18271_config)) {
result = -ENODEV; result = -EINVAL;
goto out_free;
}
break;
case EM2874_BOARD_KWORLD_UB435Q_V2:
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2874_lgdt3305_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
dvb->i2c_client_tuner = client; /* Attach the demodulator. */
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&kworld_ub435q_v2_config)) {
result = -EINVAL;
goto out_free;
} }
break; break;
case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595: case EM2874_BOARD_KWORLD_UB435Q_V3:
{ {
struct i2c_adapter *adapter;
struct i2c_client *client; struct i2c_client *client;
struct i2c_board_info info = {}; struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];
struct lgdt3306a_config lgdt3306a_config; struct i2c_board_info board_info = {
struct si2157_config si2157_config = {}; .type = "tda18212",
.addr = 0x60,
/* attach demod */ .platform_data = &kworld_ub435q_v3_config,
lgdt3306a_config = hauppauge_01595_lgdt3306a_config; };
lgdt3306a_config.fe = &dvb->fe[0];
lgdt3306a_config.i2c_adapter = &adapter;
strlcpy(info.type, "lgdt3306a", sizeof(info.type));
if (dev->ts == PRIMARY_TS)
info.addr = 0x59;
else
info.addr = 0x0e;
info.platform_data = &lgdt3306a_config;
request_module(info.type);
client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus],
&info);
if (client == NULL || client->dev.driver == NULL) {
result = -ENODEV;
goto out_free;
}
if (!try_module_get(client->dev.driver->owner)) { dvb->fe[0] = dvb_attach(lgdt3305_attach,
i2c_unregister_device(client); &em2874_lgdt3305_nogate_dev,
result = -ENODEV; &dev->i2c_adap[dev->def_i2c_bus]);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free; goto out_free;
} }
dvb->i2c_client_demod = client;
/* attach tuner */ /* attach tuner */
si2157_config.fe = dvb->fe[0]; kworld_ub435q_v3_config.fe = dvb->fe[0];
si2157_config.if_port = 1; request_module("tda18212");
si2157_config.inversion = 1; client = i2c_new_device(adapter, &board_info);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
si2157_config.mdev = dev->media_dev;
#endif
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", sizeof(info.type));
if (dev->ts == PRIMARY_TS)
info.addr = 0x60;
else
info.addr = 0x62;
info.platform_data = &si2157_config;
request_module(info.type);
client = i2c_new_device(adapter, &info);
if (client == NULL || client->dev.driver == NULL) { if (client == NULL || client->dev.driver == NULL) {
module_put(dvb->i2c_client_demod->dev.driver->owner); dvb_frontend_detach(dvb->fe[0]);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
if (!try_module_get(client->dev.driver->owner)) { if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client); i2c_unregister_device(client);
module_put(dvb->i2c_client_demod->dev.driver->owner); dvb_frontend_detach(dvb->fe[0]);
i2c_unregister_device(dvb->i2c_client_demod);
result = -ENODEV; result = -ENODEV;
goto out_free; goto out_free;
} }
dvb->i2c_client_tuner = client; dvb->i2c_client_tuner = client;
break;
}
case EM2874_BOARD_PCTV_HD_MINI_80E:
dvb->fe[0] = dvb_attach(drx39xxj_attach, &dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) {
dvb->fe[0] = dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
&dev->i2c_adap[dev->def_i2c_bus],
&pinnacle_80e_dvb_config);
if (!dvb->fe[0]) {
result = -EINVAL;
goto out_free;
} }
}
break;
case EM28178_BOARD_PCTV_461E:
result = em28178_dvb_init_pctv_461e(dev);
if (result)
goto out_free;
break;
case EM28178_BOARD_PCTV_292E:
result = em28178_dvb_init_pctv_292e(dev);
if (result)
goto out_free;
break;
case EM28178_BOARD_TERRATEC_T2_STICK_HD:
result = em28178_dvb_init_terratec_t2_stick_hd(dev);
if (result)
goto out_free;
break;
case EM28178_BOARD_PLEX_PX_BCUD:
result = em28178_dvb_init_plex_px_bcud(dev);
if (result)
goto out_free;
break;
case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
result = em28174_dvb_init_hauppauge_wintv_dualhd_dvb(dev);
if (result)
goto out_free;
break;
case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_01595:
result = em28174_dvb_init_hauppauge_wintv_dualhd_01595(dev);
if (result)
goto out_free;
break; break;
default: default:
dev_err(&dev->intf->dev, dev_err(&dev->intf->dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment