static int em28xx_dvb_init()

in usb/em28xx/em28xx-dvb.c [1483:2017]


static int em28xx_dvb_init(struct em28xx *dev)
{
	int result = 0, dvb_alt = 0;
	struct em28xx_dvb *dvb;
	struct usb_device *udev;

	if (dev->is_audio_only) {
		/* Shouldn't initialize IR for this interface */
		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(*dvb), GFP_KERNEL);
	if (!dvb)
		return -ENOMEM;

	dev->dvb = dvb;
	dvb->fe[0] = NULL;
	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,
					0x0e,
					&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:
	case EM2882_BOARD_ZOLID_HYBRID_TV_STICK:
		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:
		/*
		 * Those boards could have either a zl10353 or a mt352.
		 * If the chip id isn't for zl10353, try mt352.
		 */
		dvb->fe[0] = dvb_attach(zl10353_attach,
					&em28xx_zl10353_xc3028_no_i2c_gate,
					&dev->i2c_adap[dev->def_i2c_bus]);
		if (!dvb->fe[0])
			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]) {
			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])
			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,
					0x0e,
					&dev->i2c_adap[dev->def_i2c_bus]);
		if (dvb->fe[0]) {
			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;
			}
		}
		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;
		}
		break;
	case EM2870_BOARD_REDDO_DVB_C_USB_BOX:
		/* Philips CU1216L NIM (Philips TDA10023 + Infineon TUA6034) */
		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;
			}
		}
		break;
	case EM2870_BOARD_KWORLD_A340:
		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;
		}
		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
				&dev->i2c_adap[dev->def_i2c_bus],
				&kworld_a340_config)) {
			dvb_frontend_detach(dvb->fe[0]);
			result = -EINVAL;
			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)) {
				dvb_frontend_detach(dvb->fe[0]);
				result = -EINVAL;
				goto out_free;
			}

#ifdef CONFIG_GPIOLIB
			/* 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;
	case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
	{
		struct xc5000_config cfg = {};

		hauppauge_hvr930c_init(dev);

		dvb->fe[0] = dvb_attach(drxk_attach,
					&hauppauge_930c_drxk,
					&dev->i2c_adap[dev->def_i2c_bus]);
		if (!dvb->fe[0]) {
			result = -EINVAL;
			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 */
		cfg.i2c_address  = 0x61;
		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;
		}
		if (dvb->fe[0]->ops.i2c_gate_ctrl)
			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);

		break;
	}
	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]);
		if (!dvb->fe[0]) {
			result = -EINVAL;
			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 (dvb->fe[0]->ops.i2c_gate_ctrl)
			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 1);
		if (!dvb_attach(tda18271c2dd_attach, dvb->fe[0],
				&dev->i2c_adap[dev->def_i2c_bus], 0x60)) {
			result = -EINVAL;
			goto out_free;
		}
		if (dvb->fe[0]->ops.i2c_gate_ctrl)
			dvb->fe[0]->ops.i2c_gate_ctrl(dvb->fe[0], 0);

		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])
			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;
		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 */
			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;
			}
		}
		break;
	case EM2884_BOARD_PCTV_510E:
	case EM2884_BOARD_PCTV_520E:
		pctv_520e_init(dev);

		/* 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;
			}
		}
		break;
	case EM2884_BOARD_ELGATO_EYETV_HYBRID_2008:
	case EM2884_BOARD_CINERGY_HTC_STICK:
	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;
		}

		/* Attach the demodulator. */
		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
				&dev->i2c_adap[dev->def_i2c_bus],
				&em28xx_cxd2820r_tda18271_config)) {
			result = -EINVAL;
			goto out_free;
		}
		break;
	case EM2884_BOARD_TERRATEC_HTC_USB_XS:
		terratec_htc_usb_xs_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;
		}

		/* Attach the demodulator. */
		if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
				&dev->i2c_adap[dev->def_i2c_bus],
				&em28xx_cxd2820r_tda18271_config)) {
			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;
		}

		/* 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;
	case EM2874_BOARD_KWORLD_UB435Q_V3:
	{
		struct i2c_adapter *adapter = &dev->i2c_adap[dev->def_i2c_bus];

		dvb->fe[0] = dvb_attach(lgdt3305_attach,
					&em2874_lgdt3305_nogate_dev,
					&dev->i2c_adap[dev->def_i2c_bus]);
		if (!dvb->fe[0]) {
			result = -EINVAL;
			goto out_free;
		}

		/* attach tuner */
		kworld_ub435q_v3_config.fe = dvb->fe[0];

		dvb->i2c_client_tuner = dvb_module_probe("tda18212", NULL,
							 adapter, 0x60,
							 &kworld_ub435q_v3_config);
		if (!dvb->i2c_client_tuner) {
			dvb_frontend_detach(dvb->fe[0]);
			result = -ENODEV;
			goto out_free;
		}
		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]) {
			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_461E_V2:
		result = em28178_dvb_init_pctv_461e_v2(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;
	case EM2874_BOARD_HAUPPAUGE_USB_QUADHD:
		result = em2874_dvb_init_hauppauge_usb_quadhd(dev);
		if (result)
			goto out_free;
		break;
	default:
		dev_err(&dev->intf->dev,
			"The frontend of your DVB/ATSC card isn't supported yet\n");
		break;
	}
	if (!dvb->fe[0]) {
		dev_err(&dev->intf->dev, "frontend initialization failed\n");
		result = -EINVAL;
		goto out_free;
	}
	/* define general-purpose callback pointer */
	dvb->fe[0]->callback = em28xx_tuner_callback;
	if (dvb->fe[1])
		dvb->fe[1]->callback = em28xx_tuner_callback;

	/* register everything */
	result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->intf->dev);

	if (result < 0)
		goto out_free;

	if (dev->dvb_xfer_bulk) {
		dvb_alt = 0;
	} else { /* isoc */
		dvb_alt = dev->dvb_alt_isoc;
	}

	udev = interface_to_usbdev(dev->intf);
	usb_set_interface(udev, dev->ifnum, dvb_alt);
	dev_info(&dev->intf->dev, "DVB extension successfully initialized\n");

	kref_get(&dev->ref);

ret:
	em28xx_set_mode(dev, EM28XX_SUSPEND);
	mutex_unlock(&dev->lock);
	return result;

out_free:
	em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
	kfree(dvb);
	dev->dvb = NULL;
	goto ret;
}