static int dvb_init()

in usb/cx231xx/cx231xx-dvb.c [616:1139]


static int dvb_init(struct cx231xx *dev)
{
	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 */
		return 0;
	}

	dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);

	if (dvb == NULL) {
		dev_info(dev->dev,
			 "cx231xx_dvb: memory allocation failed\n");
		return -ENOMEM;
	}
	dev->dvb = dvb;
	dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
	dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;

	tuner_i2c = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
	demod_i2c = cx231xx_get_i2c_adap(dev, dev->board.demod_i2c_master);
	mutex_lock(&dev->lock);
	cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
	cx231xx_demod_reset(dev);
	/* init frontend */
	switch (dev->model) {
	case CX231XX_BOARD_CNXT_CARRAERA:
	case CX231XX_BOARD_CNXT_RDE_250:

		dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
					&dvico_s5h1432_config,
					demod_i2c);

		if (!dev->dvb->frontend[0]) {
			dev_err(dev->dev,
				"Failed to attach s5h1432 front end\n");
			result = -EINVAL;
			goto out_free;
		}

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
			       tuner_i2c,
			       &cnxt_rde250_tunerconfig)) {
			result = -EINVAL;
			goto out_free;
		}

		break;
	case CX231XX_BOARD_CNXT_SHELBY:
	case CX231XX_BOARD_CNXT_RDU_250:

		dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
					       &xc5000_s5h1411_config,
					       demod_i2c);

		if (!dev->dvb->frontend[0]) {
			dev_err(dev->dev,
				"Failed to attach s5h1411 front end\n");
			result = -EINVAL;
			goto out_free;
		}

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		if (!dvb_attach(xc5000_attach, dev->dvb->frontend[0],
			       tuner_i2c,
			       &cnxt_rdu250_tunerconfig)) {
			result = -EINVAL;
			goto out_free;
		}
		break;
	case CX231XX_BOARD_CNXT_RDE_253S:

		dev->dvb->frontend[0] = dvb_attach(s5h1432_attach,
					&dvico_s5h1432_config,
					demod_i2c);

		if (!dev->dvb->frontend[0]) {
			dev_err(dev->dev,
				"Failed to attach s5h1432 front end\n");
			result = -EINVAL;
			goto out_free;
		}

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
			       dev->board.tuner_addr, tuner_i2c,
			       &cnxt_rde253s_tunerconfig)) {
			result = -EINVAL;
			goto out_free;
		}
		break;
	case CX231XX_BOARD_CNXT_RDU_253S:
	case CX231XX_BOARD_KWORLD_UB445_USB_HYBRID:

		dev->dvb->frontend[0] = dvb_attach(s5h1411_attach,
					       &tda18271_s5h1411_config,
					       demod_i2c);

		if (!dev->dvb->frontend[0]) {
			dev_err(dev->dev,
				"Failed to attach s5h1411 front end\n");
			result = -EINVAL;
			goto out_free;
		}

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		if (!dvb_attach(tda18271_attach, dev->dvb->frontend[0],
			       dev->board.tuner_addr, tuner_i2c,
			       &cnxt_rde253s_tunerconfig)) {
			result = -EINVAL;
			goto out_free;
		}
		break;
	case CX231XX_BOARD_HAUPPAUGE_EXETER:

		dev_info(dev->dev,
			 "%s: looking for tuner / demod on i2c bus: %d\n",
		       __func__, i2c_adapter_id(tuner_i2c));

		dev->dvb->frontend[0] = dvb_attach(lgdt3305_attach,
						&hcw_lgdt3305_config,
						demod_i2c);

		if (!dev->dvb->frontend[0]) {
			dev_err(dev->dev,
				"Failed to attach LG3305 front end\n");
			result = -EINVAL;
			goto out_free;
		}

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		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 si2165_platform_data si2165_pdata = {};

		/* attach demod */
		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;

		dev->dvb->frontend[0]->ops.i2c_gate_ctrl = NULL;

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
			dev->board.tuner_addr, tuner_i2c,
			&hcw_tda18271_config);

		dev->cx231xx_reset_analog_tuner = NULL;
		break;
	}
	case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
	{
		struct si2165_platform_data si2165_pdata = {};
		struct si2157_config si2157_config = {};

		/* attach demod */
		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;

		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_955Q:
	{
		struct si2157_config si2157_config = {};
		struct lgdt3306a_config lgdt3306a_config = {};

		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;

		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_PV_PLAYTV_USB_HYBRID:
	case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:

		dev_info(dev->dev,
			 "%s: looking for demod on i2c bus: %d\n",
			 __func__, i2c_adapter_id(tuner_i2c));

		dev->dvb->frontend[0] = dvb_attach(mb86a20s_attach,
						&pv_mb86a20s_config,
						demod_i2c);

		if (!dev->dvb->frontend[0]) {
			dev_err(dev->dev,
				"Failed to attach mb86a20s demod\n");
			result = -EINVAL;
			goto out_free;
		}

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		dvb_attach(tda18271_attach, dev->dvb->frontend[0],
			   dev->board.tuner_addr, tuner_i2c,
			   &pv_tda18271_config);
		break;

	case CX231XX_BOARD_EVROMEDIA_FULL_HYBRID_FULLHD:
	{
		struct si2157_config si2157_config = {};
		struct si2168_config si2168_config = {};

		/* attach demodulator chip */
		si2168_config.ts_mode = SI2168_TS_SERIAL; /* from *.inf file */
		si2168_config.fe = &dev->dvb->frontend[0];
		si2168_config.i2c_adapter = &adapter;
		si2168_config.ts_clock_inv = true;

		/* 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;

		/* attach tuner chip */
		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;

		/* 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_ASTROMETA_T2HYBRID:
	{
		struct mn88473_config mn88473_config = {};

		/* attach demodulator chip */
		mn88473_config.i2c_wr_max = 16;
		mn88473_config.xtal = 25000000;
		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;

		/* define general-purpose callback pointer */
		dvb->frontend[0]->callback = cx231xx_tuner_callback;

		/* 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;

		/* 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 = {};

		/* 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;

		/* 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[0]->callback = cx231xx_tuner_callback;
		dvb->frontend[1]->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, 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:
		dev_err(dev->dev,
			"%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
			dev->name);
		break;
	}
	if (!dvb->frontend[0]) {
		dev_err(dev->dev,
		       "%s/2: frontend initialization failed\n", dev->name);
		result = -EINVAL;
		goto out_free;
	}

	/* register everything */
	result = register_dvb(dvb, THIS_MODULE, dev, dev->dev);

	if (result < 0)
		goto out_free;


	dev_info(dev->dev, "Successfully loaded cx231xx-dvb\n");

ret:
	cx231xx_set_mode(dev, CX231XX_SUSPEND);
	mutex_unlock(&dev->lock);
	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;
}