18 changed files with 12060 additions and 11 deletions
			
			
		| @ -0,0 +1,24 @@ | |||
| --- a/drivers/hisilicon/atags/tag-chiptrim.c
 | |||
| +++ b/drivers/hisilicon/atags/tag-chiptrim.c
 | |||
| @@ -59,7 +59,7 @@ static int __init parse_chiptrim(const struct tag *tag, void *fdt)
 | |||
|  	int ix; | |||
|  	int ret; | |||
|  	int node; | |||
| -	char buf[12];
 | |||
| +	char buf[20];
 | |||
|   | |||
|  	if (tag->hdr.size <= (sizeof(struct tag_header) >> 2)) { | |||
|  		pr_err("%s: bad tag format.\n", __func__); | |||
| --- a/drivers/hisilicon/atags/tag-net.c	2020-03-25 11:27:19.138225245 +0000
 | |||
| +++ b/drivers/hisilicon/atags/tag-net.c	2020-03-25 11:27:02.498266476 +0000
 | |||
| @@ -91,7 +91,7 @@
 | |||
|  { | |||
|  	int err; | |||
|  	int node, index = 0; | |||
| -	char path[16];
 | |||
| +	char path[20];
 | |||
|  	char phy_intf[16]; | |||
|  	char *str, *nxt; | |||
|  	int count; | |||
| -- 
 | |||
| 2.17.1 | |||
| @ -0,0 +1,238 @@ | |||
| ---
 | |||
|  drivers/media/dvb-core/dvb-usb-ids.h        |   2 + | |||
|  drivers/media/usb/dvb-usb/Kconfig           |   2 + | |||
|  drivers/media/usb/dvb-usb/dib0700.h         |   2 + | |||
|  drivers/media/usb/dvb-usb/dib0700_core.c    |  25 ++++- | |||
|  drivers/media/usb/dvb-usb/dib0700_devices.c | 105 ++++++++++++++++++++ | |||
|  5 files changed, 135 insertions(+), 1 deletion(-) | |||
| 
 | |||
| diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
 | |||
| index 0a46580b..512275c7 100644
 | |||
| --- a/drivers/media/dvb-core/dvb-usb-ids.h
 | |||
| +++ b/drivers/media/dvb-core/dvb-usb-ids.h
 | |||
| @@ -70,6 +70,7 @@
 | |||
|  #define USB_VID_EVOLUTEPC			0x1e59 | |||
|  #define USB_VID_AZUREWAVE			0x13d3 | |||
|  #define USB_VID_TECHNISAT			0x14f7 | |||
| +#define USB_VID_MICROSOFT			0x045e
 | |||
|   | |||
|  /* Product IDs */ | |||
|  #define USB_PID_ADSTECH_USB2_COLD			0xa333 | |||
| @@ -389,4 +390,5 @@
 | |||
|  #define USB_PID_PCTV_2002E_SE                           0x025d | |||
|  #define USB_PID_SVEON_STV27                             0xd3af | |||
|  #define USB_PID_TURBOX_DTT_2000                         0xd3a4 | |||
| +#define USB_PID_XBOX_ONE_TUNER                          0x02d5
 | |||
|  #endif | |||
| diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
 | |||
| index 128eee61..d8e3106d 100644
 | |||
| --- a/drivers/media/usb/dvb-usb/Kconfig
 | |||
| +++ b/drivers/media/usb/dvb-usb/Kconfig
 | |||
| @@ -75,6 +75,7 @@ config DVB_USB_DIB0700
 | |||
|  	select DVB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT | |||
|  	select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT | |||
|  	select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT | |||
| +	select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT
 | |||
|  	select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT | |||
|  	select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT | |||
|  	select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT | |||
| @@ -83,6 +84,7 @@ config DVB_USB_DIB0700
 | |||
|  	select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT | |||
|  	select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT | |||
|  	select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT | |||
| +	select MEDIA_TUNER_TDA18250 if MEDIA_SUBDRV_AUTOSELECT
 | |||
|  	help | |||
|  	  Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The | |||
|  	  USB bridge is also present in devices having the DiB7700 DVB-T-USB | |||
| diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
 | |||
| index 8fd8f5b4..5f291284 100644
 | |||
| --- a/drivers/media/usb/dvb-usb/dib0700.h
 | |||
| +++ b/drivers/media/usb/dvb-usb/dib0700.h
 | |||
| @@ -51,6 +51,8 @@ struct dib0700_state {
 | |||
|  	int (*read_status)(struct dvb_frontend *, enum fe_status *); | |||
|  	int (*sleep)(struct dvb_frontend* fe); | |||
|  	u8 buf[255]; | |||
| +	struct i2c_client *i2c_client_demod;
 | |||
| +	struct i2c_client *i2c_client_tuner;
 | |||
|  }; | |||
|   | |||
|  extern int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion, | |||
| diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
 | |||
| index 49dd3ea2..e4f3793a 100644
 | |||
| --- a/drivers/media/usb/dvb-usb/dib0700_core.c
 | |||
| +++ b/drivers/media/usb/dvb-usb/dib0700_core.c
 | |||
| @@ -872,10 +872,33 @@ static int dib0700_probe(struct usb_interface *intf,
 | |||
|  	return -ENODEV; | |||
|  } | |||
|   | |||
| +static void dib0700_disconnect(struct usb_interface *intf)
 | |||
| +{
 | |||
| +	struct dvb_usb_device *d = usb_get_intfdata(intf);
 | |||
| +	struct dib0700_state *st = d->priv;
 | |||
| +	struct i2c_client *client;
 | |||
| +
 | |||
| +	/* remove I2C client for tuner */
 | |||
| +	client = st->i2c_client_tuner;
 | |||
| +	if (client) {
 | |||
| +		module_put(client->dev.driver->owner);
 | |||
| +		i2c_unregister_device(client);
 | |||
| +	}
 | |||
| +
 | |||
| +	/* remove I2C client for demodulator */
 | |||
| +	client = st->i2c_client_demod;
 | |||
| +	if (client) {
 | |||
| +		module_put(client->dev.driver->owner);
 | |||
| +		i2c_unregister_device(client);
 | |||
| +	}
 | |||
| +
 | |||
| +	dvb_usb_device_exit(intf);
 | |||
| +}
 | |||
| +
 | |||
|  static struct usb_driver dib0700_driver = { | |||
|  	.name       = "dvb_usb_dib0700", | |||
|  	.probe      = dib0700_probe, | |||
| -	.disconnect = dvb_usb_device_exit,
 | |||
| +	.disconnect = dib0700_disconnect,
 | |||
|  	.id_table   = dib0700_usb_id_table, | |||
|  }; | |||
|   | |||
| diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
 | |||
| index e1316c7b..2b6c9d3c 100644
 | |||
| --- a/drivers/media/usb/dvb-usb/dib0700_devices.c
 | |||
| +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
 | |||
| @@ -23,6 +23,8 @@
 | |||
|  #include "dib0090.h" | |||
|  #include "lgdt3305.h" | |||
|  #include "mxl5007t.h" | |||
| +#include "mn88472.h"
 | |||
| +#include "tda18250.h"
 | |||
|   | |||
|  static int force_lna_activation; | |||
|  module_param(force_lna_activation, int, 0644); | |||
| @@ -3705,6 +3708,89 @@
 | |||
|  			  &hcw_mxl5007t_config) == NULL ? -ENODEV : 0; | |||
|  } | |||
|   | |||
| +static int xbox_one_attach(struct dvb_usb_adapter *adap)
 | |||
| +{
 | |||
| +	struct dib0700_state *st = adap->dev->priv;
 | |||
| +	struct i2c_client *client_demod, *client_tuner;
 | |||
| +	struct dvb_usb_device *d = adap->dev;
 | |||
| +	struct mn88472_config mn88472_config = { };
 | |||
| +	struct tda18250_config tda18250_config;
 | |||
| +	struct i2c_board_info info;
 | |||
| +
 | |||
| +	st->fw_use_new_i2c_api = 1;
 | |||
| +	st->disable_streaming_master_mode = 1;
 | |||
| +
 | |||
| +	/* fe power enable */
 | |||
| +	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
 | |||
| +	msleep(30);
 | |||
| +	dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
 | |||
| +	msleep(30);
 | |||
| +
 | |||
| +	/* demod reset */
 | |||
| +	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 | |||
| +	msleep(30);
 | |||
| +	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
 | |||
| +	msleep(30);
 | |||
| +	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
 | |||
| +	msleep(30);
 | |||
| +
 | |||
| +	/* attach demod */
 | |||
| +	mn88472_config.fe = &adap->fe_adap[0].fe;
 | |||
| +	mn88472_config.i2c_wr_max = 22;
 | |||
| +	mn88472_config.xtal = 20500000;
 | |||
| +	mn88472_config.ts_mode = PARALLEL_TS_MODE;
 | |||
| +	mn88472_config.ts_clock = FIXED_TS_CLOCK;
 | |||
| +	memset(&info, 0, sizeof(struct i2c_board_info));
 | |||
| +	strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
 | |||
| +	info.addr = 0x18;
 | |||
| +	info.platform_data = &mn88472_config;
 | |||
| +	request_module(info.type);
 | |||
| +	client_demod = i2c_new_device(&d->i2c_adap, &info);
 | |||
| +	if (client_demod == NULL || client_demod->dev.driver == NULL)
 | |||
| +		goto fail_demod_device;
 | |||
| +	if (!try_module_get(client_demod->dev.driver->owner))
 | |||
| +		goto fail_demod_module;
 | |||
| +
 | |||
| +	st->i2c_client_demod = client_demod;
 | |||
| +
 | |||
| +	adap->fe_adap[0].fe = mn88472_config.get_dvb_frontend(client_demod);
 | |||
| +
 | |||
| +	/* attach tuner */
 | |||
| +	memset(&tda18250_config, 0, sizeof(tda18250_config));
 | |||
| +	tda18250_config.if_dvbt_6 = 3950;
 | |||
| +	tda18250_config.if_dvbt_7 = 4450;
 | |||
| +	tda18250_config.if_dvbt_8 = 4950;
 | |||
| +	tda18250_config.if_dvbc_6 = 4950;
 | |||
| +	tda18250_config.if_dvbc_8 = 4950;
 | |||
| +	tda18250_config.if_atsc = 4079;
 | |||
| +	tda18250_config.loopthrough = true;
 | |||
| +	tda18250_config.xtal_freq = TDA18250_XTAL_FREQ_27MHZ;
 | |||
| +	tda18250_config.fe = adap->fe_adap[0].fe;
 | |||
| +
 | |||
| +	memset(&info, 0, sizeof(struct i2c_board_info));
 | |||
| +	strlcpy(info.type, "tda18250", I2C_NAME_SIZE);
 | |||
| +	info.addr = 0x60;
 | |||
| +	info.platform_data = &tda18250_config;
 | |||
| +
 | |||
| +	request_module(info.type);
 | |||
| +	client_tuner = i2c_new_device(&adap->dev->i2c_adap, &info);
 | |||
| +	if (client_tuner == NULL || client_tuner->dev.driver == NULL)
 | |||
| +		goto fail_tuner_device;
 | |||
| +	if (!try_module_get(client_tuner->dev.driver->owner))
 | |||
| +		goto fail_tuner_module;
 | |||
| +
 | |||
| +	st->i2c_client_tuner = client_tuner;
 | |||
| +	return 0;
 | |||
| +
 | |||
| +fail_tuner_module:
 | |||
| +	i2c_unregister_device(client_tuner);
 | |||
| +fail_tuner_device:
 | |||
| +	module_put(client_demod->dev.driver->owner);
 | |||
| +fail_demod_module:
 | |||
| +	i2c_unregister_device(client_demod);
 | |||
| +fail_demod_device:
 | |||
| +	return -ENODEV;
 | |||
| +}
 | |||
|   | |||
|  /* DVB-USB and USB stuff follows */ | |||
|  struct usb_device_id dib0700_usb_id_table[] = { | |||
| @@ -3794,6 +3880,7 @@
 | |||
|  /* 80 */{ USB_DEVICE(USB_VID_ELGATO,	USB_PID_ELGATO_EYETV_DTT_2) }, | |||
|  	{ USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E) }, | |||
|  	{ USB_DEVICE(USB_VID_PCTV,      USB_PID_PCTV_2002E_SE) }, | |||
| +	{ USB_DEVICE(USB_VID_MICROSOFT,	USB_PID_XBOX_ONE_TUNER) },
 | |||
|  	{ 0 }		/* Terminating entry */ | |||
|  }; | |||
|  MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); | |||
| @@ -4959,6 +5046,25 @@
 | |||
|  					    RC_BIT_NEC, | |||
|  			.change_protocol  = dib0700_change_protocol, | |||
|  		}, | |||
| +	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
 | |||
| +		.num_adapters = 1,
 | |||
| +		.adapter = {
 | |||
| +			{
 | |||
| +				.num_frontends = 1,
 | |||
| +				.fe = {{
 | |||
| +					.frontend_attach = xbox_one_attach,
 | |||
| +
 | |||
| +					DIB0700_DEFAULT_STREAMING_CONFIG(0x82),
 | |||
| +				} },
 | |||
| +			},
 | |||
| +		},
 | |||
| +		.num_device_descs = 1,
 | |||
| +		.devices = {
 | |||
| +			{ "Microsoft Xbox One Digital TV Tuner",
 | |||
| +				{ &dib0700_usb_id_table[83], NULL },
 | |||
| +				{ NULL },
 | |||
| +			},
 | |||
| +		},
 | |||
|  	}, | |||
|  }; | |||
|   | |||
| -- 
 | |||
| 2.17.1 | |||
| 
 | |||
								
									
										File diff suppressed because it is too large
									
								
							
						
					| @ -0,0 +1,834 @@ | |||
| ---
 | |||
|  drivers/media/dvb-frontends/mn88472.h        |  45 +- | |||
|  drivers/staging/media/mn88472/mn88472.c      | 525 ++++++++++--------- | |||
|  drivers/staging/media/mn88472/mn88472_priv.h |  11 +- | |||
|  3 files changed, 310 insertions(+), 271 deletions(-) | |||
| 
 | |||
| diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h
 | |||
| index 095294d2..32363252 100644
 | |||
| --- a/drivers/media/dvb-frontends/mn88472.h
 | |||
| +++ b/drivers/media/dvb-frontends/mn88472.h
 | |||
| @@ -19,23 +19,33 @@
 | |||
|   | |||
|  #include <linux/dvb/frontend.h> | |||
|   | |||
| -enum ts_clock {
 | |||
| -	VARIABLE_TS_CLOCK,
 | |||
| -	FIXED_TS_CLOCK,
 | |||
| -};
 | |||
| +/**
 | |||
| + * struct mn88472_config - Platform data for the mn88472 driver
 | |||
| + * @xtal: Clock frequency.
 | |||
| + * @ts_mode: TS mode.
 | |||
| + * @ts_clock: TS clock config.
 | |||
| + * @i2c_wr_max: Max number of bytes driver writes to I2C at once.
 | |||
| + * @get_dvb_frontend: Get DVB frontend.
 | |||
| + */
 | |||
|   | |||
| -enum ts_mode {
 | |||
| -	SERIAL_TS_MODE,
 | |||
| -	PARALLEL_TS_MODE,
 | |||
| -};
 | |||
| +/* Define old names for backward compatibility */
 | |||
| +#define VARIABLE_TS_CLOCK   MN88472_TS_CLK_VARIABLE
 | |||
| +#define FIXED_TS_CLOCK      MN88472_TS_CLK_FIXED
 | |||
| +#define SERIAL_TS_MODE      MN88472_TS_MODE_SERIAL
 | |||
| +#define PARALLEL_TS_MODE    MN88472_TS_MODE_PARALLEL
 | |||
|   | |||
|  struct mn88472_config { | |||
| -	/*
 | |||
| -	 * Max num of bytes given I2C adapter could write at once.
 | |||
| -	 * Default: none
 | |||
| -	 */
 | |||
| -	u16 i2c_wr_max;
 | |||
| +	unsigned int xtal;
 | |||
| +
 | |||
| +#define MN88472_TS_MODE_SERIAL      0
 | |||
| +#define MN88472_TS_MODE_PARALLEL    1
 | |||
| +	int ts_mode;
 | |||
|   | |||
| +#define MN88472_TS_CLK_FIXED        0
 | |||
| +#define MN88472_TS_CLK_VARIABLE     1
 | |||
| +	int ts_clock;
 | |||
| +
 | |||
| +	u16 i2c_wr_max;
 | |||
|   | |||
|  	/* Everything after that is returned by the driver. */ | |||
|   | |||
| @@ -43,14 +53,7 @@ struct mn88472_config {
 | |||
|  	 * DVB frontend. | |||
|  	 */ | |||
|  	struct dvb_frontend **fe; | |||
| -
 | |||
| -	/*
 | |||
| -	 * Xtal frequency.
 | |||
| -	 * Hz
 | |||
| -	 */
 | |||
| -	u32 xtal;
 | |||
| -	int ts_mode;
 | |||
| -	int ts_clock;
 | |||
| +	struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
 | |||
|  }; | |||
|   | |||
|  #endif | |||
| diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c
 | |||
| index cf2e96bc..18fb2df1 100644
 | |||
| --- a/drivers/staging/media/mn88472/mn88472.c
 | |||
| +++ b/drivers/staging/media/mn88472/mn88472.c
 | |||
| @@ -17,28 +17,90 @@
 | |||
|  #include "mn88472_priv.h" | |||
|   | |||
|  static int mn88472_get_tune_settings(struct dvb_frontend *fe, | |||
| -	struct dvb_frontend_tune_settings *s)
 | |||
| +				     struct dvb_frontend_tune_settings *s)
 | |||
|  { | |||
| -	s->min_delay_ms = 800;
 | |||
| +	s->min_delay_ms = 1000;
 | |||
|  	return 0; | |||
|  } | |||
|   | |||
| +static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status)
 | |||
| +{
 | |||
| +	struct i2c_client *client = fe->demodulator_priv;
 | |||
| +	struct mn88472_dev *dev = i2c_get_clientdata(client);
 | |||
| +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 | |||
| +	int ret;
 | |||
| +	unsigned int utmp;
 | |||
| +
 | |||
| +	if (!dev->active) {
 | |||
| +		ret = -EAGAIN;
 | |||
| +		goto err;
 | |||
| +	}
 | |||
| +
 | |||
| +	switch (c->delivery_system) {
 | |||
| +	case SYS_DVBT:
 | |||
| +		ret = regmap_read(dev->regmap[0], 0x7f, &utmp);
 | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
| +		if ((utmp & 0x0f) >= 0x09)
 | |||
| +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 | |||
| +				  FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 | |||
| +		else
 | |||
| +			*status = 0;
 | |||
| +		break;
 | |||
| +	case SYS_DVBT2:
 | |||
| +		ret = regmap_read(dev->regmap[2], 0x92, &utmp);
 | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
| +		if ((utmp & 0x0f) >= 0x0d)
 | |||
| +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 | |||
| +				  FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 | |||
| +		else if ((utmp & 0x0f) >= 0x0a)
 | |||
| +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 | |||
| +				  FE_HAS_VITERBI;
 | |||
| +		else if ((utmp & 0x0f) >= 0x07)
 | |||
| +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
 | |||
| +		else
 | |||
| +			*status = 0;
 | |||
| +		break;
 | |||
| +	case SYS_DVBC_ANNEX_A:
 | |||
| +		ret = regmap_read(dev->regmap[1], 0x84, &utmp);
 | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
| +		if ((utmp & 0x0f) >= 0x08)
 | |||
| +			*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
 | |||
| +				  FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 | |||
| +		else
 | |||
| +			*status = 0;
 | |||
| +		break;
 | |||
| +	default:
 | |||
| +		ret = -EINVAL;
 | |||
| +		goto err;
 | |||
| +	}
 | |||
| +
 | |||
| +	return 0;
 | |||
| +err:
 | |||
| +	dev_dbg(&client->dev, "failed=%d\n", ret);
 | |||
| +	return ret;
 | |||
| +}
 | |||
| +
 | |||
|  static int mn88472_set_frontend(struct dvb_frontend *fe) | |||
|  { | |||
|  	struct i2c_client *client = fe->demodulator_priv; | |||
|  	struct mn88472_dev *dev = i2c_get_clientdata(client); | |||
|  	struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |||
|  	int ret, i; | |||
| -	u32 if_frequency = 0;
 | |||
| -	u64 tmp;
 | |||
| -	u8 delivery_system_val, if_val[3], bw_val[7], bw_val2;
 | |||
| +	unsigned int utmp;
 | |||
| +	u32 if_frequency;
 | |||
| +	u8 buf[3], delivery_system_val, bandwidth_val, *bandwidth_vals_ptr;
 | |||
| +	u8 reg_bank0_b4_val, reg_bank0_cd_val, reg_bank0_d4_val;
 | |||
| +	u8 reg_bank0_d6_val;
 | |||
|   | |||
|  	dev_dbg(&client->dev, | |||
| -			"delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n",
 | |||
| -			c->delivery_system, c->modulation,
 | |||
| -			c->frequency, c->symbol_rate, c->inversion);
 | |||
| +		"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n",
 | |||
| +		c->delivery_system, c->modulation, c->frequency,
 | |||
| +		c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id);
 | |||
|   | |||
| -	if (!dev->warm) {
 | |||
| +	if (!dev->active) {
 | |||
|  		ret = -EAGAIN; | |||
|  		goto err; | |||
|  	} | |||
| @@ -46,39 +108,64 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
 | |||
|  	switch (c->delivery_system) { | |||
|  	case SYS_DVBT: | |||
|  		delivery_system_val = 0x02; | |||
| +		reg_bank0_b4_val = 0x00;
 | |||
| +		reg_bank0_cd_val = 0x1f;
 | |||
| +		reg_bank0_d4_val = 0x0a;
 | |||
| +		reg_bank0_d6_val = 0x48;
 | |||
|  		break; | |||
|  	case SYS_DVBT2: | |||
|  		delivery_system_val = 0x03; | |||
| +		reg_bank0_b4_val = 0xf6;
 | |||
| +		reg_bank0_cd_val = 0x01;
 | |||
| +		reg_bank0_d4_val = 0x09;
 | |||
| +		reg_bank0_d6_val = 0x46;
 | |||
|  		break; | |||
|  	case SYS_DVBC_ANNEX_A: | |||
|  		delivery_system_val = 0x04; | |||
| +		reg_bank0_b4_val = 0x00;
 | |||
| +		reg_bank0_cd_val = 0x17;
 | |||
| +		reg_bank0_d4_val = 0x09;
 | |||
| +		reg_bank0_d6_val = 0x48;
 | |||
|  		break; | |||
|  	default: | |||
|  		ret = -EINVAL; | |||
|  		goto err; | |||
|  	} | |||
|   | |||
| -	if (c->bandwidth_hz <= 5000000) {
 | |||
| -		memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7);
 | |||
| -		bw_val2 = 0x03;
 | |||
| -	} else if (c->bandwidth_hz <= 6000000) {
 | |||
| -		/* IF 3570000 Hz, BW 6000000 Hz */
 | |||
| -		memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7);
 | |||
| -		bw_val2 = 0x02;
 | |||
| -	} else if (c->bandwidth_hz <= 7000000) {
 | |||
| -		/* IF 4570000 Hz, BW 7000000 Hz */
 | |||
| -		memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7);
 | |||
| -		bw_val2 = 0x01;
 | |||
| -	} else if (c->bandwidth_hz <= 8000000) {
 | |||
| -		/* IF 4570000 Hz, BW 8000000 Hz */
 | |||
| -		memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7);
 | |||
| -		bw_val2 = 0x00;
 | |||
| -	} else {
 | |||
| -		ret = -EINVAL;
 | |||
| -		goto err;
 | |||
| +	switch (c->delivery_system) {
 | |||
| +	case SYS_DVBT:
 | |||
| +	case SYS_DVBT2:
 | |||
| +		switch (c->bandwidth_hz) {
 | |||
| +		case 5000000:
 | |||
| +			bandwidth_vals_ptr = "\xe5\x99\x9a\x1b\xa9\x1b\xa9";
 | |||
| +			bandwidth_val = 0x03;
 | |||
| +			break;
 | |||
| +		case 6000000:
 | |||
| +			bandwidth_vals_ptr = "\xbf\x55\x55\x15\x6b\x15\x6b";
 | |||
| +			bandwidth_val = 0x02;
 | |||
| +			break;
 | |||
| +		case 7000000:
 | |||
| +			bandwidth_vals_ptr = "\xa4\x00\x00\x0f\x2c\x0f\x2c";
 | |||
| +			bandwidth_val = 0x01;
 | |||
| +			break;
 | |||
| +		case 8000000:
 | |||
| +			bandwidth_vals_ptr = "\x8f\x80\x00\x08\xee\x08\xee";
 | |||
| +			bandwidth_val = 0x00;
 | |||
| +			break;
 | |||
| +		default:
 | |||
| +			ret = -EINVAL;
 | |||
| +			goto err;
 | |||
| +		}
 | |||
| +		break;
 | |||
| +	case SYS_DVBC_ANNEX_A:
 | |||
| +		bandwidth_vals_ptr = NULL;
 | |||
| +		bandwidth_val = 0x00;
 | |||
| +		break;
 | |||
| +	default:
 | |||
| +		break;
 | |||
|  	} | |||
|   | |||
| -	/* program tuner */
 | |||
| +	/* Program tuner */
 | |||
|  	if (fe->ops.tuner_ops.set_params) { | |||
|  		ret = fe->ops.tuner_ops.set_params(fe); | |||
|  		if (ret) | |||
| @@ -91,20 +178,10 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
 | |||
|  			goto err; | |||
|   | |||
|  		dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); | |||
| -	}
 | |||
| -
 | |||
| -	/* Calculate IF registers ( (1<<24)*IF / Xtal ) */
 | |||
| -	tmp =  div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2),
 | |||
| -				   dev->xtal);
 | |||
| -	if_val[0] = ((tmp >> 16) & 0xff);
 | |||
| -	if_val[1] = ((tmp >>  8) & 0xff);
 | |||
| -	if_val[2] = ((tmp >>  0) & 0xff);
 | |||
| -
 | |||
| -	ret = regmap_write(dev->regmap[2], 0xfb, 0x13);
 | |||
| -	ret = regmap_write(dev->regmap[2], 0xef, 0x13);
 | |||
| -	ret = regmap_write(dev->regmap[2], 0xf9, 0x13);
 | |||
| -	if (ret)
 | |||
| +	} else {
 | |||
| +		ret = -EINVAL;
 | |||
|  		goto err; | |||
| +	}
 | |||
|   | |||
|  	ret = regmap_write(dev->regmap[2], 0x00, 0x66); | |||
|  	if (ret) | |||
| @@ -118,157 +195,81 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
 | |||
|  	ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); | |||
|  	if (ret) | |||
|  		goto err; | |||
| -	ret = regmap_write(dev->regmap[2], 0x04, bw_val2);
 | |||
| +	ret = regmap_write(dev->regmap[2], 0x04, bandwidth_val);
 | |||
|  	if (ret) | |||
|  		goto err; | |||
|   | |||
| -	for (i = 0; i < sizeof(if_val); i++) {
 | |||
| -		ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]);
 | |||
| +	/* IF */
 | |||
| +	utmp = DIV_ROUND_CLOSEST_ULL((u64)if_frequency * 0x1000000, dev->clk);
 | |||
| +	buf[0] = (utmp >> 16) & 0xff;
 | |||
| +	buf[1] = (utmp >>  8) & 0xff;
 | |||
| +	buf[2] = (utmp >>  0) & 0xff;
 | |||
| +	for (i = 0; i < 3; i++) {
 | |||
| +		ret = regmap_write(dev->regmap[2], 0x10 + i, buf[i]);
 | |||
|  		if (ret) | |||
|  			goto err; | |||
|  	} | |||
|   | |||
| -	for (i = 0; i < sizeof(bw_val); i++) {
 | |||
| -		ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]);
 | |||
| -		if (ret)
 | |||
| -			goto err;
 | |||
| +	/* Bandwidth */
 | |||
| +	if (bandwidth_vals_ptr) {
 | |||
| +		for (i = 0; i < 7; i++) {
 | |||
| +			ret = regmap_write(dev->regmap[2], 0x13 + i,
 | |||
| +					   bandwidth_vals_ptr[i]);
 | |||
| +			if (ret)
 | |||
| +				goto err;
 | |||
| +		}
 | |||
|  	} | |||
|   | |||
| +	ret = regmap_write(dev->regmap[0], 0xb4, reg_bank0_b4_val);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
| +	ret = regmap_write(dev->regmap[0], 0xcd, reg_bank0_cd_val);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
| +	ret = regmap_write(dev->regmap[0], 0xd4, reg_bank0_d4_val);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
| +	ret = regmap_write(dev->regmap[0], 0xd6, reg_bank0_d6_val);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
| +
 | |||
|  	switch (c->delivery_system) { | |||
|  	case SYS_DVBT: | |||
|  		ret = regmap_write(dev->regmap[0], 0x07, 0x26); | |||
| -		ret = regmap_write(dev->regmap[0], 0xb0, 0x0a);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xb4, 0x00);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xcd, 0x1f);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd4, 0x0a);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd6, 0x48);
 | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
|  		ret = regmap_write(dev->regmap[0], 0x00, 0xba); | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
|  		ret = regmap_write(dev->regmap[0], 0x01, 0x13); | |||
|  		if (ret) | |||
|  			goto err; | |||
|  		break; | |||
|  	case SYS_DVBT2: | |||
|  		ret = regmap_write(dev->regmap[2], 0x2b, 0x13); | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
|  		ret = regmap_write(dev->regmap[2], 0x4f, 0x05); | |||
| +		if (ret)
 | |||
| +			goto err;
 | |||
|  		ret = regmap_write(dev->regmap[1], 0xf6, 0x05); | |||
| -		ret = regmap_write(dev->regmap[0], 0xb0, 0x0a);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xb4, 0xf6);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xcd, 0x01);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd4, 0x09);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd6, 0x46);
 | |||
| -		ret = regmap_write(dev->regmap[2], 0x30, 0x80);
 | |||
| -		ret = regmap_write(dev->regmap[2], 0x32, 0x00);
 | |||
|  		if (ret) | |||
|  			goto err; | |||
| -		break;
 | |||
| -	case SYS_DVBC_ANNEX_A:
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xb0, 0x0b);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xb4, 0x00);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xcd, 0x17);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd4, 0x09);
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd6, 0x48);
 | |||
| -		ret = regmap_write(dev->regmap[1], 0x00, 0xb0);
 | |||
| +		ret = regmap_write(dev->regmap[2], 0x32, c->stream_id);
 | |||
|  		if (ret) | |||
|  			goto err; | |||
|  		break; | |||
| -	default:
 | |||
| -		ret = -EINVAL;
 | |||
| -		goto err;
 | |||
| -	}
 | |||
| -
 | |||
| -	ret = regmap_write(dev->regmap[0], 0x46, 0x00);
 | |||
| -	ret = regmap_write(dev->regmap[0], 0xae, 0x00);
 | |||
| -
 | |||
| -	switch (dev->ts_mode) {
 | |||
| -	case SERIAL_TS_MODE:
 | |||
| -		ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
 | |||
| -		break;
 | |||
| -	case PARALLEL_TS_MODE:
 | |||
| -		ret = regmap_write(dev->regmap[2], 0x08, 0x00);
 | |||
| +	case SYS_DVBC_ANNEX_A:
 | |||
|  		break; | |||
|  	default: | |||
| -		dev_dbg(&client->dev, "ts_mode error: %d\n", dev->ts_mode);
 | |||
| -		ret = -EINVAL;
 | |||
| -		goto err;
 | |||
| -	}
 | |||
| -
 | |||
| -	switch (dev->ts_clock) {
 | |||
| -	case VARIABLE_TS_CLOCK:
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd9, 0xe3);
 | |||
|  		break; | |||
| -	case FIXED_TS_CLOCK:
 | |||
| -		ret = regmap_write(dev->regmap[0], 0xd9, 0xe1);
 | |||
| -		break;
 | |||
| -	default:
 | |||
| -		dev_dbg(&client->dev, "ts_clock error: %d\n", dev->ts_clock);
 | |||
| -		ret = -EINVAL;
 | |||
| -		goto err;
 | |||
|  	} | |||
|   | |||
| -	/* Reset demod */
 | |||
| +	/* Reset FSM */
 | |||
|  	ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); | |||
|  	if (ret) | |||
|  		goto err; | |||
|   | |||
| -	dev->delivery_system = c->delivery_system;
 | |||
| -
 | |||
| -	return 0;
 | |||
| -err:
 | |||
| -	dev_dbg(&client->dev, "failed=%d\n", ret);
 | |||
| -	return ret;
 | |||
| -}
 | |||
| -
 | |||
| -static int mn88472_read_status(struct dvb_frontend *fe, enum fe_status *status)
 | |||
| -{
 | |||
| -	struct i2c_client *client = fe->demodulator_priv;
 | |||
| -	struct mn88472_dev *dev = i2c_get_clientdata(client);
 | |||
| -	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
 | |||
| -	int ret;
 | |||
| -	unsigned int utmp;
 | |||
| -	int lock = 0;
 | |||
| -
 | |||
| -	*status = 0;
 | |||
| -
 | |||
| -	if (!dev->warm) {
 | |||
| -		ret = -EAGAIN;
 | |||
| -		goto err;
 | |||
| -	}
 | |||
| -
 | |||
| -	switch (c->delivery_system) {
 | |||
| -	case SYS_DVBT:
 | |||
| -		ret = regmap_read(dev->regmap[0], 0x7F, &utmp);
 | |||
| -		if (ret)
 | |||
| -			goto err;
 | |||
| -		if ((utmp & 0xF) >= 0x09)
 | |||
| -			lock = 1;
 | |||
| -		break;
 | |||
| -	case SYS_DVBT2:
 | |||
| -		ret = regmap_read(dev->regmap[2], 0x92, &utmp);
 | |||
| -		if (ret)
 | |||
| -			goto err;
 | |||
| -		if ((utmp & 0xF) >= 0x07)
 | |||
| -			*status |= FE_HAS_SIGNAL;
 | |||
| -		if ((utmp & 0xF) >= 0x0a)
 | |||
| -			*status |= FE_HAS_CARRIER;
 | |||
| -		if ((utmp & 0xF) >= 0x0d)
 | |||
| -			*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
 | |||
| -		break;
 | |||
| -	case SYS_DVBC_ANNEX_A:
 | |||
| -		ret = regmap_read(dev->regmap[1], 0x84, &utmp);
 | |||
| -		if (ret)
 | |||
| -			goto err;
 | |||
| -		if ((utmp & 0xF) >= 0x08)
 | |||
| -			lock = 1;
 | |||
| -		break;
 | |||
| -	default:
 | |||
| -		ret = -EINVAL;
 | |||
| -		goto err;
 | |||
| -	}
 | |||
| -
 | |||
| -	if (lock)
 | |||
| -		*status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
 | |||
| -				FE_HAS_SYNC | FE_HAS_LOCK;
 | |||
| -
 | |||
|  	return 0; | |||
|  err: | |||
|  	dev_dbg(&client->dev, "failed=%d\n", ret); | |||
| @@ -279,93 +280,107 @@ static int mn88472_init(struct dvb_frontend *fe)
 | |||
|  { | |||
|  	struct i2c_client *client = fe->demodulator_priv; | |||
|  	struct mn88472_dev *dev = i2c_get_clientdata(client); | |||
| -	int ret, len, remaining;
 | |||
| -	const struct firmware *fw = NULL;
 | |||
| -	u8 *fw_file = MN88472_FIRMWARE;
 | |||
| -	unsigned int tmp;
 | |||
| +	int ret, len, rem;
 | |||
| +	unsigned int utmp;
 | |||
| +	const struct firmware *firmware;
 | |||
| +	const char *name = MN88472_FIRMWARE;
 | |||
|   | |||
|  	dev_dbg(&client->dev, "\n"); | |||
|   | |||
| -	/* set cold state by default */
 | |||
| -	dev->warm = false;
 | |||
| -
 | |||
| -	/* power on */
 | |||
| +	/* Power up */
 | |||
|  	ret = regmap_write(dev->regmap[2], 0x05, 0x00); | |||
|  	if (ret) | |||
|  		goto err; | |||
| -
 | |||
| -	ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2);
 | |||
| +	ret = regmap_write(dev->regmap[2], 0x0b, 0x00);
 | |||
|  	if (ret) | |||
|  		goto err; | |||
| -
 | |||
| -	/* check if firmware is already running */
 | |||
| -	ret = regmap_read(dev->regmap[0], 0xf5, &tmp);
 | |||
| +	ret = regmap_write(dev->regmap[2], 0x0c, 0x00);
 | |||
|  	if (ret) | |||
|  		goto err; | |||
|   | |||
| -	if (!(tmp & 0x1)) {
 | |||
| -		dev_info(&client->dev, "firmware already running\n");
 | |||
| -		dev->warm = true;
 | |||
| -		return 0;
 | |||
| -	}
 | |||
| +	/* Check if firmware is already running */
 | |||
| +	ret = regmap_read(dev->regmap[0], 0xf5, &utmp);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
| +	if (!(utmp & 0x01))
 | |||
| +		goto warm;
 | |||
|   | |||
| -	/* request the firmware, this will block and timeout */
 | |||
| -	ret = request_firmware(&fw, fw_file, &client->dev);
 | |||
| +	ret = request_firmware(&firmware, name, &client->dev);
 | |||
|  	if (ret) { | |||
| -		dev_err(&client->dev, "firmare file '%s' not found\n",
 | |||
| -				fw_file);
 | |||
| +		dev_err(&client->dev, "firmware file '%s' not found\n", name);
 | |||
|  		goto err; | |||
|  	} | |||
|   | |||
| -	dev_info(&client->dev, "downloading firmware from file '%s'\n",
 | |||
| -			fw_file);
 | |||
| +	dev_info(&client->dev, "downloading firmware from file '%s'\n", name);
 | |||
|   | |||
|  	ret = regmap_write(dev->regmap[0], 0xf5, 0x03); | |||
|  	if (ret) | |||
| -		goto firmware_release;
 | |||
| -
 | |||
| -	for (remaining = fw->size; remaining > 0;
 | |||
| -			remaining -= (dev->i2c_wr_max - 1)) {
 | |||
| -		len = remaining;
 | |||
| -		if (len > (dev->i2c_wr_max - 1))
 | |||
| -			len = dev->i2c_wr_max - 1;
 | |||
| +		goto err_release_firmware;
 | |||
|   | |||
| +	for (rem = firmware->size; rem > 0; rem -= (dev->i2c_write_max - 1)) {
 | |||
| +		len = min(dev->i2c_write_max - 1, rem);
 | |||
|  		ret = regmap_bulk_write(dev->regmap[0], 0xf6, | |||
| -				&fw->data[fw->size - remaining], len);
 | |||
| +					&firmware->data[firmware->size - rem],
 | |||
| +					len);
 | |||
|  		if (ret) { | |||
| -			dev_err(&client->dev,
 | |||
| -					"firmware download failed=%d\n", ret);
 | |||
| -			goto firmware_release;
 | |||
| +			dev_err(&client->dev, "firmware download failed %d\n",
 | |||
| +				ret);
 | |||
| +			goto err_release_firmware;
 | |||
|  		} | |||
|  	} | |||
|   | |||
| -	/* parity check of firmware */
 | |||
| -	ret = regmap_read(dev->regmap[0], 0xf8, &tmp);
 | |||
| -	if (ret) {
 | |||
| -		dev_err(&client->dev,
 | |||
| -				"parity reg read failed=%d\n", ret);
 | |||
| -		goto firmware_release;
 | |||
| -	}
 | |||
| -	if (tmp & 0x10) {
 | |||
| -		dev_err(&client->dev,
 | |||
| -				"firmware parity check failed=0x%x\n", tmp);
 | |||
| -		goto firmware_release;
 | |||
| +	/* Parity check of firmware */
 | |||
| +	ret = regmap_read(dev->regmap[0], 0xf8, &utmp);
 | |||
| +	if (ret)
 | |||
| +		goto err_release_firmware;
 | |||
| +	if (utmp & 0x10) {
 | |||
| +		ret = -EINVAL;
 | |||
| +		dev_err(&client->dev, "firmware did not run\n");
 | |||
| +		goto err_release_firmware;
 | |||
|  	} | |||
| -	dev_err(&client->dev, "firmware parity check succeeded=0x%x\n", tmp);
 | |||
|   | |||
|  	ret = regmap_write(dev->regmap[0], 0xf5, 0x00); | |||
|  	if (ret) | |||
| -		goto firmware_release;
 | |||
| +		goto err_release_firmware;
 | |||
| +
 | |||
| +	release_firmware(firmware);
 | |||
| +warm:
 | |||
| +	/* TS config */
 | |||
| +	switch (dev->ts_mode) {
 | |||
| +	case SERIAL_TS_MODE:
 | |||
| +		utmp = 0x1d;
 | |||
| +		break;
 | |||
| +	case PARALLEL_TS_MODE:
 | |||
| +		utmp = 0x00;
 | |||
| +		break;
 | |||
| +	default:
 | |||
| +		ret = -EINVAL;
 | |||
| +		goto err;
 | |||
| +	}
 | |||
| +	ret = regmap_write(dev->regmap[2], 0x08, utmp);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
|   | |||
| -	release_firmware(fw);
 | |||
| -	fw = NULL;
 | |||
| +	switch (dev->ts_clk) {
 | |||
| +	case VARIABLE_TS_CLOCK:
 | |||
| +		utmp = 0xe3;
 | |||
| +		break;
 | |||
| +	case FIXED_TS_CLOCK:
 | |||
| +		utmp = 0xe1;
 | |||
| +		break;
 | |||
| +	default:
 | |||
| +		ret = -EINVAL;
 | |||
| +		goto err;
 | |||
| +	}
 | |||
| +	ret = regmap_write(dev->regmap[0], 0xd9, utmp);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
|   | |||
| -	/* warm state */
 | |||
| -	dev->warm = true;
 | |||
| +	dev->active = true;
 | |||
|   | |||
|  	return 0; | |||
| -firmware_release:
 | |||
| -	release_firmware(fw);
 | |||
| +err_release_firmware:
 | |||
| +	release_firmware(firmware);
 | |||
|  err: | |||
|  	dev_dbg(&client->dev, "failed=%d\n", ret); | |||
|  	return ret; | |||
| @@ -379,18 +394,17 @@ static int mn88472_sleep(struct dvb_frontend *fe)
 | |||
|   | |||
|  	dev_dbg(&client->dev, "\n"); | |||
|   | |||
| -	/* power off */
 | |||
| +	/* Power down */
 | |||
| +	ret = regmap_write(dev->regmap[2], 0x0c, 0x30);
 | |||
| +	if (ret)
 | |||
| +		goto err;
 | |||
|  	ret = regmap_write(dev->regmap[2], 0x0b, 0x30); | |||
| -
 | |||
|  	if (ret) | |||
|  		goto err; | |||
| -
 | |||
|  	ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | |||
|  	if (ret) | |||
|  		goto err; | |||
|   | |||
| -	dev->delivery_system = SYS_UNDEFINED;
 | |||
| -
 | |||
|  	return 0; | |||
|  err: | |||
|  	dev_dbg(&client->dev, "failed=%d\n", ret); | |||
| @@ -434,10 +448,19 @@ static struct dvb_frontend_ops mn88472_ops = {
 | |||
|  	.read_status = mn88472_read_status, | |||
|  }; | |||
|   | |||
| +static struct dvb_frontend *mn88472_get_dvb_frontend(struct i2c_client *client)
 | |||
| +{
 | |||
| +	struct mn88472_dev *dev = i2c_get_clientdata(client);
 | |||
| +
 | |||
| +	dev_dbg(&client->dev, "\n");
 | |||
| +
 | |||
| +	return &dev->fe;
 | |||
| +}
 | |||
| +
 | |||
|  static int mn88472_probe(struct i2c_client *client, | |||
| -		const struct i2c_device_id *id)
 | |||
| +			 const struct i2c_device_id *id)
 | |||
|  { | |||
| -	struct mn88472_config *config = client->dev.platform_data;
 | |||
| +	struct mn88472_config *pdata = client->dev.platform_data;
 | |||
|  	struct mn88472_dev *dev; | |||
|  	int ret; | |||
|  	unsigned int utmp; | |||
| @@ -448,23 +471,16 @@ static int mn88472_probe(struct i2c_client *client,
 | |||
|   | |||
|  	dev_dbg(&client->dev, "\n"); | |||
|   | |||
| -	/* Caller really need to provide pointer for frontend we create. */
 | |||
| -	if (config->fe == NULL) {
 | |||
| -		dev_err(&client->dev, "frontend pointer not defined\n");
 | |||
| -		ret = -EINVAL;
 | |||
| -		goto err;
 | |||
| -	}
 | |||
| -
 | |||
|  	dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |||
| -	if (dev == NULL) {
 | |||
| +	if (!dev) {
 | |||
|  		ret = -ENOMEM; | |||
|  		goto err; | |||
|  	} | |||
|   | |||
| -	dev->i2c_wr_max = config->i2c_wr_max;
 | |||
| -	dev->xtal = config->xtal;
 | |||
| -	dev->ts_mode = config->ts_mode;
 | |||
| -	dev->ts_clock = config->ts_clock;
 | |||
| +	dev->i2c_write_max = pdata->i2c_wr_max ? pdata->i2c_wr_max : ~0;
 | |||
| +	dev->clk = pdata->xtal;
 | |||
| +	dev->ts_mode = pdata->ts_mode;
 | |||
| +	dev->ts_clk = pdata->ts_clock;
 | |||
|  	dev->client[0] = client; | |||
|  	dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); | |||
|  	if (IS_ERR(dev->regmap[0])) { | |||
| @@ -472,18 +488,28 @@ static int mn88472_probe(struct i2c_client *client,
 | |||
|  		goto err_kfree; | |||
|  	} | |||
|   | |||
| -	/* check demod answers to I2C */
 | |||
| -	ret = regmap_read(dev->regmap[0], 0x00, &utmp);
 | |||
| +	/* Check demod answers with correct chip id */
 | |||
| +	ret = regmap_read(dev->regmap[0], 0xff, &utmp);
 | |||
|  	if (ret) | |||
|  		goto err_regmap_0_regmap_exit; | |||
|   | |||
| +	dev_dbg(&client->dev, "chip id=%02x\n", utmp);
 | |||
| +
 | |||
| +	if (utmp != 0x02) {
 | |||
| +		ret = -ENODEV;
 | |||
| +		goto err_regmap_0_regmap_exit;
 | |||
| +	}
 | |||
| +
 | |||
|  	/* | |||
| -	 * Chip has three I2C addresses for different register pages. Used
 | |||
| +	 * Chip has three I2C addresses for different register banks. Used
 | |||
|  	 * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, | |||
| -	 * 0x1a and 0x1c, in order to get own I2C client for each register page.
 | |||
| +	 * 0x1a and 0x1c, in order to get own I2C client for each register bank.
 | |||
| +	 *
 | |||
| +	 * Also, register bank 2 do not support sequential I/O. Only single
 | |||
| +	 * register write or read is allowed to that bank.
 | |||
|  	 */ | |||
|  	dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); | |||
| -	if (dev->client[1] == NULL) {
 | |||
| +	if (!dev->client[1]) {
 | |||
|  		ret = -ENODEV; | |||
|  		dev_err(&client->dev, "I2C registration failed\n"); | |||
|  		if (ret) | |||
| @@ -497,7 +523,7 @@ static int mn88472_probe(struct i2c_client *client,
 | |||
|  	i2c_set_clientdata(dev->client[1], dev); | |||
|   | |||
|  	dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); | |||
| -	if (dev->client[2] == NULL) {
 | |||
| +	if (!dev->client[2]) {
 | |||
|  		ret = -ENODEV; | |||
|  		dev_err(&client->dev, "2nd I2C registration failed\n"); | |||
|  		if (ret) | |||
| @@ -510,15 +536,25 @@ static int mn88472_probe(struct i2c_client *client,
 | |||
|  	} | |||
|  	i2c_set_clientdata(dev->client[2], dev); | |||
|   | |||
| -	/* create dvb_frontend */
 | |||
| +	/* Sleep because chip is active by default */
 | |||
| +	ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
 | |||
| +	if (ret)
 | |||
| +		goto err_regmap_2_regmap_exit;
 | |||
| +
 | |||
| +	/* Create dvb frontend */
 | |||
|  	memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); | |||
|  	dev->fe.demodulator_priv = client; | |||
| -	*config->fe = &dev->fe;
 | |||
| +	*pdata->fe = &dev->fe;
 | |||
|  	i2c_set_clientdata(client, dev); | |||
|   | |||
| -	dev_info(&client->dev, "Panasonic MN88472 successfully attached\n");
 | |||
| -	return 0;
 | |||
| +	/* Setup callbacks */
 | |||
| +	pdata->get_dvb_frontend = mn88472_get_dvb_frontend;
 | |||
|   | |||
| +	dev_info(&client->dev, "Panasonic MN88472 successfully identified\n");
 | |||
| +
 | |||
| +	return 0;
 | |||
| +err_regmap_2_regmap_exit:
 | |||
| +	regmap_exit(dev->regmap[2]);
 | |||
|  err_client_2_i2c_unregister_device: | |||
|  	i2c_unregister_device(dev->client[2]); | |||
|  err_regmap_1_regmap_exit: | |||
| @@ -561,11 +597,12 @@ MODULE_DEVICE_TABLE(i2c, mn88472_id_table);
 | |||
|   | |||
|  static struct i2c_driver mn88472_driver = { | |||
|  	.driver = { | |||
| -		.name	= "mn88472",
 | |||
| +		.name = "mn88472",
 | |||
| +		.suppress_bind_attrs = true,
 | |||
|  	}, | |||
| -	.probe		= mn88472_probe,
 | |||
| -	.remove		= mn88472_remove,
 | |||
| -	.id_table	= mn88472_id_table,
 | |||
| +	.probe    = mn88472_probe,
 | |||
| +	.remove   = mn88472_remove,
 | |||
| +	.id_table = mn88472_id_table,
 | |||
|  }; | |||
|   | |||
|  module_i2c_driver(mn88472_driver); | |||
| diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h
 | |||
| index 1a0de9e4..cdf2597a 100644
 | |||
| --- a/drivers/staging/media/mn88472/mn88472_priv.h
 | |||
| +++ b/drivers/staging/media/mn88472/mn88472_priv.h
 | |||
| @@ -28,12 +28,11 @@ struct mn88472_dev {
 | |||
|  	struct i2c_client *client[3]; | |||
|  	struct regmap *regmap[3]; | |||
|  	struct dvb_frontend fe; | |||
| -	u16 i2c_wr_max;
 | |||
| -	enum fe_delivery_system delivery_system;
 | |||
| -	bool warm; /* FW running */
 | |||
| -	u32 xtal;
 | |||
| -	int ts_mode;
 | |||
| -	int ts_clock;
 | |||
| +	u16 i2c_write_max;
 | |||
| +	unsigned int clk;
 | |||
| +	unsigned int active:1;
 | |||
| +	unsigned int ts_mode:1;
 | |||
| +	unsigned int ts_clk:1;
 | |||
|  }; | |||
|   | |||
|  #endif | |||
| -- 
 | |||
| 2.17.1 | |||
| 
 | |||
| @ -0,0 +1,629 @@ | |||
| diff -Nur a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
 | |||
| --- a/Documentation/video4linux/CARDLIST.em28xx	2017-07-31 15:25:12.000000000 +0200
 | |||
| +++ b/Documentation/video4linux/CARDLIST.em28xx	2019-04-02 08:35:00.919204500 +0200
 | |||
| @@ -96,3 +96,5 @@
 | |||
|   95 -> Leadtek VC100                            (em2861)        [0413:6f07] | |||
|   96 -> Terratec Cinergy T2 Stick HD             (em28178) | |||
|   97 -> Elgato EyeTV Hybrid 2008 INT             (em2884)        [0fd9:0018] | |||
| + 98 -> Hauppauge WinTV-dualHD DVB               (em28174)       [2040:0265]
 | |||
| + 
 | |||
| diff -Nur a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
 | |||
| --- a/drivers/media/usb/em28xx/em28xx.h	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/em28xx/em28xx.h	2019-04-02 08:30:40.196114900 +0200
 | |||
| @@ -145,6 +145,7 @@
 | |||
|  #define EM2861_BOARD_LEADTEK_VC100                95 | |||
|  #define EM28178_BOARD_TERRATEC_T2_STICK_HD        96 | |||
|  #define EM2884_BOARD_ELGATO_EYETV_HYBRID_2008     97 | |||
| +#define EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB  98
 | |||
|   | |||
|  /* Limits minimum and default number of buffers */ | |||
|  #define EM28XX_MIN_BUF 4 | |||
| @@ -213,6 +214,9 @@
 | |||
|  /* max. number of button state polling addresses */ | |||
|  #define EM28XX_NUM_BUTTON_ADDRESSES_MAX		5 | |||
|   | |||
| +#define PRIMARY_TS	0
 | |||
| +#define SECONDARY_TS	1
 | |||
| +
 | |||
|  enum em28xx_mode { | |||
|  	EM28XX_SUSPEND, | |||
|  	EM28XX_ANALOG_MODE, | |||
| @@ -412,6 +416,7 @@
 | |||
|  enum em28xx_led_role { | |||
|  	EM28XX_LED_ANALOG_CAPTURING = 0, | |||
|  	EM28XX_LED_DIGITAL_CAPTURING, | |||
| +	EM28XX_LED_DIGITAL_CAPTURING_TS2,
 | |||
|  	EM28XX_LED_ILLUMINATION, | |||
|  	EM28XX_NUM_LED_ROLES, /* must be the last */ | |||
|  }; | |||
| @@ -458,6 +463,7 @@
 | |||
|  	unsigned int mts_firmware:1; | |||
|  	unsigned int max_range_640_480:1; | |||
|  	unsigned int has_dvb:1; | |||
| +	unsigned int has_dual_ts:1;
 | |||
|  	unsigned int is_webcam:1; | |||
|  	unsigned int valid:1; | |||
|  	unsigned int has_ir_i2c:1; | |||
| @@ -608,7 +614,6 @@
 | |||
|  	struct em28xx_IR *ir; | |||
|   | |||
|  	/* generic device properties */ | |||
| -	char name[30];		/* name (including minor) of the device */
 | |||
|  	int model;		/* index in the device_data struct */ | |||
|  	int devno;		/* marks the number of this device */ | |||
|  	enum em28xx_chip_id chip_id; | |||
| @@ -619,6 +624,7 @@
 | |||
|  	unsigned int is_audio_only:1; | |||
|  	enum em28xx_int_audio_type int_audio_type; | |||
|  	enum em28xx_usb_audio_type usb_audio_type; | |||
| +	unsigned char name[32];
 | |||
|   | |||
|  	struct em28xx_board board; | |||
|   | |||
| @@ -677,9 +683,12 @@
 | |||
|   | |||
|  	/* usb transfer */ | |||
|  	struct usb_device *udev;	/* the usb device */ | |||
| +	struct usb_interface *intf;	// the usb interface
 | |||
|  	u8 ifnum;		/* number of the assigned usb interface */ | |||
|  	u8 analog_ep_isoc;	/* address of isoc endpoint for analog */ | |||
|  	u8 analog_ep_bulk;	/* address of bulk endpoint for analog */ | |||
| +	u8 dvb_ep_isoc_ts2;	/* address of isoc endpoint for DVB TS2*/
 | |||
| +	u8 dvb_ep_bulk_ts2;	/* address of bulk endpoint for DVB TS2*/
 | |||
|  	u8 dvb_ep_isoc;		/* address of isoc endpoint for DVB */ | |||
|  	u8 dvb_ep_bulk;		/* address of bulk endpoint for DVB */ | |||
|  	int alt;		/* alternate setting */ | |||
| @@ -693,6 +702,8 @@
 | |||
|  	int dvb_alt_isoc;	/* alternate setting for DVB isoc transfers */ | |||
|  	unsigned int dvb_max_pkt_size_isoc;	/* isoc max packet size of the | |||
|  						   selected DVB ep at dvb_alt */ | |||
| +	unsigned int dvb_max_pkt_size_isoc_ts2;	/* isoc max packet size of the
 | |||
| +						   selected DVB ep at dvb_alt */
 | |||
|  	unsigned int dvb_xfer_bulk:1;		/* use bulk instead of isoc | |||
|  						   transfers for DVB          */ | |||
|  	char urb_buf[URB_MAX_CTRL_SIZE];	/* urb control msg buffer */ | |||
| @@ -718,6 +729,15 @@
 | |||
|  	/* Snapshot button input device */ | |||
|  	char snapshot_button_path[30];	/* path of the input dev */ | |||
|  	struct input_dev *sbutton_input_dev; | |||
| +
 | |||
| +#ifdef CONFIG_MEDIA_CONTROLLER
 | |||
| +	struct media_device *media_dev;
 | |||
| +	struct media_entity input_ent[MAX_EM28XX_INPUT];
 | |||
| +	struct media_pad input_pad[MAX_EM28XX_INPUT];
 | |||
| +#endif
 | |||
| +
 | |||
| +	struct em28xx	*dev_next;
 | |||
| +	int ts;
 | |||
|  }; | |||
|   | |||
|  #define kref_to_dev(d) container_of(d, struct em28xx, ref) | |||
| diff -Nur a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
 | |||
| --- a/drivers/media/usb/em28xx/em28xx-cards.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/em28xx/em28xx-cards.c	2019-04-02 08:43:27.288403900 +0200
 | |||
| @@ -491,6 +491,30 @@
 | |||
|  	{-1,                             -1,   -1,     -1}, | |||
|  }; | |||
|   | |||
| +/* 2040:0265 Hauppauge WinTV-dualHD DVB Isoc
 | |||
| + * 2040:8265 Hauppauge WinTV-dualHD DVB Bulk
 | |||
| + * reg 0x80/0x84:
 | |||
| + * GPIO_0: Yellow LED tuner 1, 0=on, 1=off
 | |||
| + * GPIO_1: Green LED tuner 1, 0=on, 1=off
 | |||
| + * GPIO_2: Yellow LED tuner 2, 0=on, 1=off
 | |||
| + * GPIO_3: Green LED tuner 2, 0=on, 1=off
 | |||
| + * GPIO_5: Reset #2, 0=active
 | |||
| + * GPIO_6: Reset #1, 0=active
 | |||
| + */
 | |||
| +static struct em28xx_reg_seq hauppauge_dualhd_dvb[] = {
 | |||
| +	{EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,      0},
 | |||
| +	{0x0d,                         0xff, 0xff,    200},
 | |||
| +	{0x50,                         0x04, 0xff,    300},
 | |||
| +	{EM2874_R80_GPIO_P0_CTRL,      0xbf, 0xff,    100}, /* demod 1 reset */
 | |||
| +	{EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,    100},
 | |||
| +	{EM2874_R80_GPIO_P0_CTRL,      0xdf, 0xff,    100}, /* demod 2 reset */
 | |||
| +	{EM2874_R80_GPIO_P0_CTRL,      0xff, 0xff,    100},
 | |||
| +	{EM2874_R5F_TS_ENABLE,         0x44, 0xff,     50},
 | |||
| +	{EM2874_R5D_TS1_PKT_SIZE,      0x05, 0xff,     50},
 | |||
| +	{EM2874_R5E_TS2_PKT_SIZE,      0x05, 0xff,     50},
 | |||
| +	{-1,                             -1,   -1,     -1},
 | |||
| +};
 | |||
| +
 | |||
|  /* | |||
|   *  Button definitions | |||
|   */ | |||
| @@ -560,6 +584,22 @@
 | |||
|  	{-1, 0, 0, 0}, | |||
|  }; | |||
|   | |||
| +static struct em28xx_led hauppauge_dualhd_leds[] = {
 | |||
| +	{
 | |||
| +		.role      = EM28XX_LED_DIGITAL_CAPTURING,
 | |||
| +		.gpio_reg  = EM2874_R80_GPIO_P0_CTRL,
 | |||
| +		.gpio_mask = EM_GPIO_1,
 | |||
| +		.inverted  = 1,
 | |||
| +	},
 | |||
| +	{
 | |||
| +		.role      = EM28XX_LED_DIGITAL_CAPTURING_TS2,
 | |||
| +		.gpio_reg  = EM2874_R80_GPIO_P0_CTRL,
 | |||
| +		.gpio_mask = EM_GPIO_3,
 | |||
| +		.inverted  = 1,
 | |||
| +	},
 | |||
| +	{-1, 0, 0, 0},
 | |||
| +};
 | |||
| +
 | |||
|  /* | |||
|   *  Board definitions | |||
|   */ | |||
| @@ -2288,6 +2328,20 @@
 | |||
|  		.has_dvb       = 1, | |||
|  		.ir_codes      = RC_MAP_TERRATEC_SLIM_2, | |||
|  	}, | |||
| +	/* 2040:0265 Hauppauge WinTV-dualHD (DVB version) Isoc.
 | |||
| +	 * 2040:8265 Hauppauge WinTV-dualHD (DVB version) Bulk.
 | |||
| +	 * Empia EM28274, 2x Silicon Labs Si2168, 2x Silicon Labs Si2157 */
 | |||
| +	[EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB] = {
 | |||
| +		.name          = "Hauppauge WinTV-dualHD DVB",
 | |||
| +		.def_i2c_bus   = 1,
 | |||
| +		.i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
 | |||
| +		.tuner_type    = TUNER_ABSENT,
 | |||
| +		.tuner_gpio    = hauppauge_dualhd_dvb,
 | |||
| +		.has_dvb       = 1,
 | |||
| +		.has_dual_ts   = 1,
 | |||
| +		.ir_codes      = RC_MAP_HAUPPAUGE,
 | |||
| +		.leds          = hauppauge_dualhd_leds,
 | |||
| +	},
 | |||
|  }; | |||
|  EXPORT_SYMBOL_GPL(em28xx_boards); | |||
|   | |||
| @@ -2411,6 +2465,10 @@
 | |||
|  			.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, | |||
|  	{ USB_DEVICE(0x2040, 0x651f), | |||
|  			.driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850 }, | |||
| +	{ USB_DEVICE(0x2040, 0x0265),
 | |||
| +			.driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
 | |||
| +	{ USB_DEVICE(0x2040, 0x8265),
 | |||
| +			.driver_info = EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB },
 | |||
|  	{ USB_DEVICE(0x0438, 0xb002), | |||
|  			.driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, | |||
|  	{ USB_DEVICE(0x2001, 0xf112), | |||
| @@ -2804,6 +2862,7 @@
 | |||
|  	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850: | |||
|  	case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: | |||
|  	case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C: | |||
| +	case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
 | |||
|  	{ | |||
|  		struct tveeprom tv; | |||
|   | |||
| @@ -3013,6 +3072,8 @@
 | |||
|  */ | |||
|  static void em28xx_release_resources(struct em28xx *dev) | |||
|  { | |||
| +	struct usb_device *udev = interface_to_usbdev(dev->intf);
 | |||
| +	
 | |||
|  	/*FIXME: I2C IR should be disconnected */ | |||
|   | |||
|  	mutex_lock(&dev->lock); | |||
| @@ -3021,7 +3082,8 @@
 | |||
|  		em28xx_i2c_unregister(dev, 1); | |||
|  	em28xx_i2c_unregister(dev, 0); | |||
|   | |||
| -	usb_put_dev(dev->udev);
 | |||
| +	if (dev->ts == PRIMARY_TS)
 | |||
| +		usb_put_dev(udev);
 | |||
|   | |||
|  	/* Mark device as unused */ | |||
|  	clear_bit(dev->devno, em28xx_devused); | |||
| @@ -3063,6 +3125,7 @@
 | |||
|  	const char *chip_name = default_chip_name; | |||
|   | |||
|  	dev->udev = udev; | |||
| +	dev->intf = interface;
 | |||
|  	mutex_init(&dev->ctrl_urb_lock); | |||
|  	spin_lock_init(&dev->slock); | |||
|   | |||
| @@ -3220,6 +3283,35 @@
 | |||
|  	return 0; | |||
|  } | |||
|   | |||
| +int em28xx_duplicate_dev(struct em28xx *dev)
 | |||
| +{
 | |||
| +	int nr;
 | |||
| +	struct em28xx *sec_dev = kzalloc(sizeof(*sec_dev), GFP_KERNEL);
 | |||
| +
 | |||
| +	if (sec_dev == NULL) {
 | |||
| +		dev->dev_next = NULL;
 | |||
| +		return -ENOMEM;
 | |||
| +	}
 | |||
| +	memcpy(sec_dev, dev, sizeof(sizeof(*sec_dev)));
 | |||
| +	/* Check to see next free device and mark as used */
 | |||
| +	do {
 | |||
| +		nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
 | |||
| +		if (nr >= EM28XX_MAXBOARDS) {
 | |||
| +			/* No free device slots */
 | |||
| +			printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
 | |||
| +					EM28XX_MAXBOARDS);
 | |||
| +			kfree(sec_dev);
 | |||
| +			dev->dev_next = NULL;
 | |||
| +			return -ENOMEM;
 | |||
| +		}
 | |||
| +	} while (test_and_set_bit(nr, em28xx_devused));
 | |||
| +	sec_dev->devno = nr;
 | |||
| +	snprintf(sec_dev->name, 28, "em28xx #%d", nr);
 | |||
| +	sec_dev->dev_next = NULL;
 | |||
| +	dev->dev_next = sec_dev;
 | |||
| +	return 0;
 | |||
| +}
 | |||
| +
 | |||
|  /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ | |||
|  #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03)) | |||
|   | |||
| @@ -3340,6 +3432,17 @@
 | |||
|  						} | |||
|  					} | |||
|  					break; | |||
| +				case 0x85:
 | |||
| +					if (usb_endpoint_xfer_isoc(e)) {
 | |||
| +						if (size > dev->dvb_max_pkt_size_isoc_ts2) {
 | |||
| +							dev->dvb_ep_isoc_ts2 = e->bEndpointAddress;
 | |||
| +							dev->dvb_max_pkt_size_isoc_ts2 = size;
 | |||
| +							dev->dvb_alt_isoc = i;
 | |||
| +						}
 | |||
| +					} else {
 | |||
| +						dev->dvb_ep_bulk_ts2 = e->bEndpointAddress;
 | |||
| +					}
 | |||
| +					break;
 | |||
|  				} | |||
|  			} | |||
|  			/* NOTE: | |||
| @@ -3354,6 +3457,8 @@
 | |||
|  			 *  0x83	isoc*		=> audio | |||
|  			 *  0x84	isoc		=> digital | |||
|  			 *  0x84	bulk		=> analog or digital** | |||
| +			 *  0x85	isoc		=> digital TS2
 | |||
| +			 *  0x85	bulk		=> digital TS2
 | |||
|  			 * (*: audio should always be isoc) | |||
|  			 * (**: analog, if ep 0x82 is isoc, otherwise digital) | |||
|  			 * | |||
| @@ -3422,6 +3527,10 @@
 | |||
|  	dev->has_video = has_video; | |||
|  	dev->ifnum = ifnum; | |||
|   | |||
| +	dev->ts = PRIMARY_TS;
 | |||
| +	snprintf(dev->name, 28, "em28xx");
 | |||
| +	dev->dev_next = NULL;
 | |||
| +
 | |||
|  	if (has_vendor_audio) { | |||
|  		printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n", | |||
|  		       ifnum, "(Vendor Class)"); | |||
| @@ -3491,6 +3600,65 @@
 | |||
|  			    dev->dvb_xfer_bulk ? "bulk" : "isoc"); | |||
|  	} | |||
|   | |||
| +	if (dev->board.has_dual_ts && em28xx_duplicate_dev(dev) == 0) {
 | |||
| +		dev->dev_next->ts = SECONDARY_TS;
 | |||
| +		dev->dev_next->alt   = -1;
 | |||
| +		dev->dev_next->is_audio_only = has_vendor_audio &&
 | |||
| +						!(has_video || has_dvb);
 | |||
| +		dev->dev_next->has_video = false;
 | |||
| +		dev->dev_next->ifnum = ifnum;
 | |||
| +		dev->dev_next->model = id->driver_info;
 | |||
| +
 | |||
| +		mutex_init(&dev->dev_next->lock);
 | |||
| +		retval = em28xx_init_dev(dev->dev_next, udev, interface,
 | |||
| +					dev->dev_next->devno);
 | |||
| +		if (retval)
 | |||
| +			goto err_free;
 | |||
| +
 | |||
| +		dev->dev_next->board.ir_codes = NULL; /* No IR for 2nd tuner */
 | |||
| +		dev->dev_next->board.has_ir_i2c = 0; /* No IR for 2nd tuner */
 | |||
| +
 | |||
| +		if (usb_xfer_mode < 0) {
 | |||
| +			if (dev->dev_next->board.is_webcam)
 | |||
| +				try_bulk = 1;
 | |||
| +			else
 | |||
| +				try_bulk = 0;
 | |||
| +		} else {
 | |||
| +			try_bulk = usb_xfer_mode > 0;
 | |||
| +		}
 | |||
| +
 | |||
| +		/* Select USB transfer types to use */
 | |||
| +		if (has_dvb) {
 | |||
| +			if (!dev->dvb_ep_isoc_ts2 ||
 | |||
| +			   (try_bulk && dev->dvb_ep_bulk_ts2))
 | |||
| +				dev->dev_next->dvb_xfer_bulk = 1;
 | |||
| +			printk(DRIVER_NAME "dvb ts2 set to %s mode.\n",
 | |||
| +				dev->dev_next->dvb_xfer_bulk ? "bulk" : "isoc");
 | |||
| +		}
 | |||
| +
 | |||
| +		dev->dev_next->dvb_ep_isoc = dev->dvb_ep_isoc_ts2;
 | |||
| +		dev->dev_next->dvb_ep_bulk = dev->dvb_ep_bulk_ts2;
 | |||
| +		dev->dev_next->dvb_max_pkt_size_isoc = dev->dvb_max_pkt_size_isoc_ts2;
 | |||
| +		dev->dev_next->dvb_alt_isoc = dev->dvb_alt_isoc;
 | |||
| +
 | |||
| +		/* Configuare hardware to support TS2*/
 | |||
| +		if (dev->dvb_xfer_bulk) {
 | |||
| +			/* The ep4 and ep5 are configuared for BULK */
 | |||
| +			em28xx_write_reg(dev, 0x0b, 0x96);
 | |||
| +			mdelay(100);
 | |||
| +			em28xx_write_reg(dev, 0x0b, 0x80);
 | |||
| +			mdelay(100);
 | |||
| +		} else {
 | |||
| +			/* The ep4 and ep5 are configuared for ISO */
 | |||
| +			em28xx_write_reg(dev, 0x0b, 0x96);
 | |||
| +			mdelay(100);
 | |||
| +			em28xx_write_reg(dev, 0x0b, 0x82);
 | |||
| +			mdelay(100);
 | |||
| +		}
 | |||
| +
 | |||
| +		kref_init(&dev->dev_next->ref);
 | |||
| +	}
 | |||
| +
 | |||
|  	kref_init(&dev->ref); | |||
|   | |||
|  	request_modules(dev); | |||
| @@ -3528,6 +3696,13 @@
 | |||
|  	if (!dev) | |||
|  		return; | |||
|   | |||
| +	if (dev->dev_next != NULL) {
 | |||
| +		dev->dev_next->disconnected = 1;
 | |||
| +		printk(DRIVER_NAME "Disconnecting %s\n",
 | |||
| +			dev->dev_next->name);
 | |||
| +		flush_request_modules(dev->dev_next);
 | |||
| +	}
 | |||
| +
 | |||
|  	dev->disconnected = 1; | |||
|   | |||
|  	em28xx_info("Disconnecting %s\n", dev->name); | |||
| @@ -3536,7 +3711,14 @@
 | |||
|   | |||
|  	em28xx_close_extension(dev); | |||
|   | |||
| +	if (dev->dev_next != NULL)
 | |||
| +		em28xx_release_resources(dev->dev_next);
 | |||
|  	em28xx_release_resources(dev); | |||
| +
 | |||
| +	if (dev->dev_next != NULL) {
 | |||
| +		kref_put(&dev->dev_next->ref, em28xx_free_device);
 | |||
| +		dev->dev_next = NULL;
 | |||
| +	}
 | |||
|  	kref_put(&dev->ref, em28xx_free_device); | |||
|  } | |||
|   | |||
| diff -Nur a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
 | |||
| --- a/drivers/media/usb/em28xx/em28xx-core.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/em28xx/em28xx-core.c	2019-04-02 08:30:40.204091800 +0200
 | |||
| @@ -636,10 +636,19 @@
 | |||
|  	    dev->chip_id == CHIP_ID_EM28174 || | |||
|  	    dev->chip_id == CHIP_ID_EM28178) { | |||
|  		/* The Transport Stream Enable Register moved in em2874 */ | |||
| -		rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
 | |||
| -					   start ?
 | |||
| -					       EM2874_TS1_CAPTURE_ENABLE : 0x00,
 | |||
| -					   EM2874_TS1_CAPTURE_ENABLE);
 | |||
| +		if (dev->ts == PRIMARY_TS) {
 | |||
| +			rc = em28xx_write_reg_bits(dev,
 | |||
| +				EM2874_R5F_TS_ENABLE,
 | |||
| +				start ?
 | |||
| +				EM2874_TS1_CAPTURE_ENABLE : 0x00,
 | |||
| +				EM2874_TS1_CAPTURE_ENABLE);
 | |||
| +		} else {
 | |||
| +			rc = em28xx_write_reg_bits(dev,
 | |||
| +				EM2874_R5F_TS_ENABLE,
 | |||
| +				start ?
 | |||
| +				EM2874_TS2_CAPTURE_ENABLE : 0x00,
 | |||
| +				EM2874_TS2_CAPTURE_ENABLE);
 | |||
| +		}
 | |||
|  	} else { | |||
|  		/* FIXME: which is the best order? */ | |||
|  		/* video registers are sampled by VREF */ | |||
| @@ -1073,7 +1082,11 @@
 | |||
|  	mutex_lock(&em28xx_devlist_mutex); | |||
|  	list_add_tail(&ops->next, &em28xx_extension_devlist); | |||
|  	list_for_each_entry(dev, &em28xx_devlist, devlist) { | |||
| -		ops->init(dev);
 | |||
| +		if (ops->init) {
 | |||
| +			ops->init(dev);
 | |||
| +			if (dev->dev_next != NULL)
 | |||
| +				ops->init(dev->dev_next);
 | |||
| +		}
 | |||
|  	} | |||
|  	mutex_unlock(&em28xx_devlist_mutex); | |||
|  	printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name); | |||
| @@ -1087,7 +1100,11 @@
 | |||
|   | |||
|  	mutex_lock(&em28xx_devlist_mutex); | |||
|  	list_for_each_entry(dev, &em28xx_devlist, devlist) { | |||
| -		ops->fini(dev);
 | |||
| +		if (ops->fini) {
 | |||
| +			if (dev->dev_next != NULL)
 | |||
| +				ops->fini(dev->dev_next);
 | |||
| +			ops->fini(dev);
 | |||
| +		}
 | |||
|  	} | |||
|  	list_del(&ops->next); | |||
|  	mutex_unlock(&em28xx_devlist_mutex); | |||
| @@ -1102,8 +1119,11 @@
 | |||
|  	mutex_lock(&em28xx_devlist_mutex); | |||
|  	list_add_tail(&dev->devlist, &em28xx_devlist); | |||
|  	list_for_each_entry(ops, &em28xx_extension_devlist, next) { | |||
| -		if (ops->init)
 | |||
| -			ops->init(dev);
 | |||
| +		if (ops->init) {
 | |||
| + 			ops->init(dev);
 | |||
| + 			if (dev->dev_next != NULL)
 | |||
| +				ops->init(dev->dev_next);
 | |||
| +		}
 | |||
|  	} | |||
|  	mutex_unlock(&em28xx_devlist_mutex); | |||
|  } | |||
| @@ -1114,8 +1134,11 @@
 | |||
|   | |||
|  	mutex_lock(&em28xx_devlist_mutex); | |||
|  	list_for_each_entry(ops, &em28xx_extension_devlist, next) { | |||
| -		if (ops->fini)
 | |||
| -			ops->fini(dev);
 | |||
| +		if (ops->fini) {
 | |||
| + 			if (dev->dev_next != NULL)
 | |||
| +				ops->fini(dev->dev_next);
 | |||
| + 			ops->fini(dev);
 | |||
| +		}
 | |||
|  	} | |||
|  	list_del(&dev->devlist); | |||
|  	mutex_unlock(&em28xx_devlist_mutex); | |||
| @@ -1130,6 +1153,8 @@
 | |||
|  	list_for_each_entry(ops, &em28xx_extension_devlist, next) { | |||
|  		if (ops->suspend) | |||
|  			ops->suspend(dev); | |||
| +		if (dev->dev_next != NULL)
 | |||
| +			ops->suspend(dev->dev_next);
 | |||
|  	} | |||
|  	mutex_unlock(&em28xx_devlist_mutex); | |||
|  	return 0; | |||
| @@ -1144,6 +1169,8 @@
 | |||
|  	list_for_each_entry(ops, &em28xx_extension_devlist, next) { | |||
|  		if (ops->resume) | |||
|  			ops->resume(dev); | |||
| +		if (dev->dev_next != NULL)
 | |||
| +			ops->resume(dev->dev_next);
 | |||
|  	} | |||
|  	mutex_unlock(&em28xx_devlist_mutex); | |||
|  	return 0; | |||
| diff -Nur a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
 | |||
| --- a/drivers/media/usb/em28xx/em28xx-dvb.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/em28xx/em28xx-dvb.c	2019-04-02 08:30:40.206087100 +0200
 | |||
| @@ -211,7 +211,6 @@
 | |||
|  		dvb_alt = dev->dvb_alt_isoc; | |||
|  	} | |||
|   | |||
| -	usb_set_interface(dev->udev, dev->ifnum, dvb_alt);
 | |||
|  	rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); | |||
|  	if (rc < 0) | |||
|  		return rc; | |||
| @@ -1031,8 +1030,9 @@
 | |||
|   | |||
|  static int em28xx_dvb_init(struct em28xx *dev) | |||
|  { | |||
| -	int result = 0;
 | |||
| +	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 */ | |||
| @@ -1726,6 +1726,76 @@
 | |||
|  			dvb->i2c_client_tuner = client; | |||
|  		} | |||
|  		break; | |||
| +	case EM28174_BOARD_HAUPPAUGE_WINTV_DUALHD_DVB:
 | |||
| +		{
 | |||
| +			struct i2c_adapter *adapter;
 | |||
| +			struct i2c_client *client;
 | |||
| +			struct i2c_board_info info;
 | |||
| +			struct si2168_config si2168_config;
 | |||
| +			struct si2157_config si2157_config;
 | |||
| +
 | |||
| +			/* attach demod */
 | |||
| +			memset(&si2168_config, 0, sizeof(si2168_config));
 | |||
| +			si2168_config.i2c_adapter = &adapter;
 | |||
| +			si2168_config.fe = &dvb->fe[0];
 | |||
| +			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;
 | |||
| +			}
 | |||
| +
 | |||
| +			if (!try_module_get(client->dev.driver->owner)) {
 | |||
| +				i2c_unregister_device(client);
 | |||
| +				result = -ENODEV;
 | |||
| +				goto out_free;
 | |||
| +			}
 | |||
| +
 | |||
| +			dvb->i2c_client_demod = client;
 | |||
| +
 | |||
| +			/* attach tuner */
 | |||
| +			memset(&si2157_config, 0, sizeof(si2157_config));
 | |||
| +			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);
 | |||
| +			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;
 | |||
| +			}
 | |||
| +
 | |||
| +			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;
 | |||
| +			}
 | |||
| +
 | |||
| +			dvb->i2c_client_tuner = client;
 | |||
| +
 | |||
| +		}
 | |||
| +		break;
 | |||
|  	default: | |||
|  		em28xx_errdev("/2: The frontend of your DVB/ATSC card" | |||
|  				" isn't supported yet\n"); | |||
| @@ -1747,6 +1817,14 @@
 | |||
|  	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);
 | |||
|  	em28xx_info("DVB extension successfully initialized\n"); | |||
|   | |||
|  	kref_get(&dev->ref); | |||
| diff -Nur a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
 | |||
| --- a/drivers/media/usb/em28xx/em28xx-reg.h	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/em28xx/em28xx-reg.h	2019-04-02 08:30:40.209080400 +0200
 | |||
| @@ -193,6 +193,19 @@
 | |||
|  /* em2874 registers */ | |||
|  #define EM2874_R50_IR_CONFIG    0x50 | |||
|  #define EM2874_R51_IR           0x51 | |||
| +#define EM2874_R5D_TS1_PKT_SIZE 0x5d
 | |||
| +#define EM2874_R5E_TS2_PKT_SIZE 0x5e
 | |||
| +	/*
 | |||
| +	 * For both TS1 and TS2, In isochronous mode:
 | |||
| +	 *  0x01  188 bytes
 | |||
| +	 *  0x02  376 bytes
 | |||
| +	 *  0x03  564 bytes
 | |||
| +	 *  0x04  752 bytes
 | |||
| +	 *  0x05  940 bytes
 | |||
| +	 * In bulk mode:
 | |||
| +	 *  0x01..0xff  total packet count in 188-byte
 | |||
| +	 */
 | |||
| +
 | |||
|  #define EM2874_R5F_TS_ENABLE    0x5f | |||
|   | |||
|  /* em2874/174/84, em25xx, em276x/7x/8x GPIO registers */ | |||
| @ -0,0 +1,158 @@ | |||
| diff -Nur a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
 | |||
| --- a/drivers/media/usb/dvb-usb/dib0700_core.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/dvb-usb/dib0700_core.c	2019-02-23 09:05:14.000000000 +0100
 | |||
| @@ -783,6 +783,9 @@
 | |||
|   | |||
|  	/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */ | |||
|   | |||
| +	if (intf->altsetting[0].desc.bNumEndpoints < rc_ep + 1)
 | |||
| +		return -ENODEV;
 | |||
| +
 | |||
|  	purb = usb_alloc_urb(0, GFP_KERNEL); | |||
|  	if (purb == NULL) { | |||
|  		err("rc usb alloc urb failed"); | |||
| diff -Nur a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
 | |||
| --- a/drivers/media/usb/dvb-usb/dib0700_devices.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c	2019-02-23 09:05:14.000000000 +0100
 | |||
| @@ -294,7 +294,7 @@
 | |||
|  					     stk7700d_dib7000p_mt2266_config) | |||
|  		    != 0) { | |||
|  			err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__); | |||
| -			dvb_detach(&state->dib7000p_ops);
 | |||
| +			dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  			return -ENODEV; | |||
|  		} | |||
|  	} | |||
| @@ -328,7 +328,7 @@
 | |||
|  					     stk7700d_dib7000p_mt2266_config) | |||
|  		    != 0) { | |||
|  			err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__); | |||
| -			dvb_detach(&state->dib7000p_ops);
 | |||
| +			dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  			return -ENODEV; | |||
|  		} | |||
|  	} | |||
| @@ -433,6 +433,7 @@
 | |||
|  		state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); | |||
|  		break; | |||
|  	case XC2028_RESET_CLK: | |||
| +	case XC2028_I2C_FLUSH:
 | |||
|  		break; | |||
|  	default: | |||
|  		err("%s: unknown command %d, arg %d\n", __func__, | |||
| @@ -481,7 +482,7 @@
 | |||
|  				     &stk7700ph_dib7700_xc3028_config) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", | |||
|  		    __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| @@ -1012,7 +1013,7 @@
 | |||
|  				     &dib7070p_dib7000p_config) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", | |||
|  		    __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| @@ -1070,7 +1071,7 @@
 | |||
|  				     &dib7770p_dib7000p_config) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", | |||
|  		    __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| @@ -3038,7 +3039,7 @@
 | |||
|   | |||
|  	if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|  	adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); | |||
| @@ -3091,7 +3092,7 @@
 | |||
|  	/* initialize IC 0 */ | |||
|  	if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| @@ -3121,7 +3122,7 @@
 | |||
|  	i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); | |||
|  	if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| @@ -3196,7 +3197,7 @@
 | |||
|  				1, 0x10, &tfe7790p_dib7000p_config) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", | |||
|  				__func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|  	adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, | |||
| @@ -3291,7 +3292,7 @@
 | |||
|  				     stk7070pd_dib7000p_config) != 0) { | |||
|  		err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", | |||
|  		    __func__); | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| @@ -3366,7 +3367,7 @@
 | |||
|  					     stk7070pd_dib7000p_config) != 0) { | |||
|  			err("%s: state->dib7000p_ops.i2c_enumeration failed.  Cannot continue\n", | |||
|  			    __func__); | |||
| -			dvb_detach(&state->dib7000p_ops);
 | |||
| +			dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  			return -ENODEV; | |||
|  		} | |||
|  	} | |||
| @@ -3602,7 +3603,7 @@
 | |||
|   | |||
|  	if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) { | |||
|  		/* Demodulator not found for some reason? */ | |||
| -		dvb_detach(&state->dib7000p_ops);
 | |||
| +		dvb_detach(state->dib7000p_ops.set_wbd_ref);
 | |||
|  		return -ENODEV; | |||
|  	} | |||
|   | |||
| diff -Nur a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
 | |||
| --- a/drivers/media/usb/dvb-usb/dibusb-common.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/dvb-usb/dibusb-common.c	2019-02-23 09:05:14.000000000 +0100
 | |||
| @@ -179,8 +179,20 @@
 | |||
|   | |||
|  int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val) | |||
|  { | |||
| -	u8 wbuf[1] = { offs };
 | |||
| -	return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
 | |||
| +	u8 *buf;
 | |||
| +	int rc;
 | |||
| +
 | |||
| +	buf = kmalloc(2, GFP_KERNEL);
 | |||
| +	if (!buf)
 | |||
| +		return -ENOMEM;
 | |||
| +
 | |||
| +	buf[0] = offs;
 | |||
| +
 | |||
| +	rc = dibusb_i2c_msg(d, 0x50, &buf[0], 1, &buf[1], 1);
 | |||
| +	*val = buf[1];
 | |||
| +	kfree(buf);
 | |||
| +
 | |||
| +	return rc;
 | |||
|  } | |||
|  EXPORT_SYMBOL(dibusb_read_eeprom_byte); | |||
|   | |||
| @ -0,0 +1,67 @@ | |||
| diff -Nur a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c
 | |||
| --- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c	2017-07-31 15:25:15.000000000 +0200
 | |||
| +++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c	2019-02-23 09:05:14.000000000 +0100
 | |||
| @@ -35,42 +35,51 @@
 | |||
|   | |||
|  int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type) | |||
|  { | |||
| -	struct hexline hx;
 | |||
| -	u8 reset;
 | |||
| -	int ret,pos=0;
 | |||
| +	struct hexline *hx;
 | |||
| +	u8 *buf;
 | |||
| +	int ret, pos = 0;
 | |||
| +	u16 cpu_cs_register = cypress[type].cpu_cs_register;
 | |||
| +
 | |||
| +	buf = kmalloc(sizeof(*hx), GFP_KERNEL);
 | |||
| +	if (!buf)
 | |||
| +		return -ENOMEM;
 | |||
| +	hx = (struct hexline *)buf;
 | |||
|   | |||
|  	/* stop the CPU */ | |||
| -	reset = 1;
 | |||
| -	if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
 | |||
| +	buf[0] = 1;
 | |||
| +	if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1)
 | |||
|  		err("could not stop the USB controller CPU."); | |||
|   | |||
| -	while ((ret = dvb_usb_get_hexline(fw,&hx,&pos)) > 0) {
 | |||
| -		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n",hx.addr,hx.len,hx.chk);
 | |||
| -		ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len);
 | |||
| +	while ((ret = dvb_usb_get_hexline(fw, hx, &pos)) > 0) {
 | |||
| +		deb_fw("writing to address 0x%04x (buffer: 0x%02x %02x)\n", hx->addr, hx->len, hx->chk);
 | |||
| +		ret = usb_cypress_writemem(udev, hx->addr, hx->data, hx->len);
 | |||
|   | |||
| -		if (ret != hx.len) {
 | |||
| +		if (ret != hx->len) {
 | |||
|  			err("error while transferring firmware " | |||
|  				"(transferred size: %d, block size: %d)", | |||
| -				ret,hx.len);
 | |||
| +				ret, hx->len);
 | |||
|  			ret = -EINVAL; | |||
|  			break; | |||
|  		} | |||
|  	} | |||
|  	if (ret < 0) { | |||
|  		err("firmware download failed at %d with %d",pos,ret); | |||
| +		kfree(buf);
 | |||
|  		return ret; | |||
|  	} | |||
|   | |||
|  	if (ret == 0) { | |||
|  		/* restart the CPU */ | |||
| -		reset = 0;
 | |||
| -		if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
 | |||
| +		buf[0] = 0;
 | |||
| +		if (usb_cypress_writemem(udev, cpu_cs_register, buf, 1) != 1) {
 | |||
|  			err("could not restart the USB controller CPU."); | |||
|  			ret = -EINVAL; | |||
|  		} | |||
|  	} else | |||
|  		ret = -EIO; | |||
|   | |||
| +	kfree(buf);
 | |||
| +
 | |||
|  	return ret; | |||
|  } | |||
|  EXPORT_SYMBOL(usb_cypress_load_firmware); | |||
								
									
										File diff suppressed because it is too large
									
								
							
						
					| @ -0,0 +1,36 @@ | |||
| [SMB3] Improve security, move default dialect to SMB3 from old CIFS | |||
| Due to recent publicity about security vulnerabilities in the | |||
| much older CIFS dialect, move the default dialect to the | |||
| widely accepted (and quite secure) SMB3.0 dialect from the | |||
| old default of the CIFS dialect. | |||
| 
 | |||
| We do not want to be encouraging use of less secure dialects, | |||
| and both Microsoft and CERT now strongly recommend not using the | |||
| older CIFS dialect (SMB Security Best Practices | |||
| "recommends disabling SMBv1"). | |||
| 
 | |||
| SMB3 is both secure and widely available: in Windows 8 and later, | |||
| Samba and Macs. | |||
| 
 | |||
| Users can still choose to explicitly mount with the less secure | |||
| dialect (for old servers) by choosing "vers=1.0" on the cifs | |||
| mount | |||
| 
 | |||
| Signed-off-by: Steve French <smfrench@gmail.com> | |||
| Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com> | |||
| 
 | |||
| --- a/fs/cifs/connect.c	2019-10-19 09:34:13.448215659 +0200
 | |||
| +++ b/fs/cifs/connect.c	2019-10-19 09:41:22.938494534 +0200
 | |||
| @@ -1274,9 +1274,9 @@
 | |||
|   | |||
|  	vol->actimeo = CIFS_DEF_ACTIMEO; | |||
|   | |||
| -	/* FIXME: add autonegotiation -- for now, SMB1 is default */
 | |||
| -	vol->ops = &smb1_operations;
 | |||
| -	vol->vals = &smb1_values;
 | |||
| +	/* FIXME: add autonegotiation for SMB3 or later rather than just SMB3 */
 | |||
| +	vol->ops = &smb30_operations; /* both secure and accepted widely */
 | |||
| +	vol->vals = &smb302_values;
 | |||
|   | |||
|  	if (!mountdata) | |||
|  		goto cifs_parse_mount_err; | |||
| @ -0,0 +1,50 @@ | |||
| From 89134f0918ec3bf4614ac2f9258543940e611f01 Mon Sep 17 00:00:00 2001 | |||
| From: Arnd Bergmann <arnd@arndb.de> | |||
| Date: Wed, 1 Feb 2017 18:00:14 +0100 | |||
| Subject: modules: mark __inittest/__exittest as __maybe_unused | |||
| 
 | |||
| commit 1f318a8bafcfba9f0d623f4870c4e890fd22e659 upstream. | |||
| 
 | |||
| clang warns about unused inline functions by default: | |||
| 
 | |||
| arch/arm/crypto/aes-cipher-glue.c:68:1: warning: unused function '__inittest' [-Wunused-function] | |||
| arch/arm/crypto/aes-cipher-glue.c:69:1: warning: unused function '__exittest' [-Wunused-function] | |||
| 
 | |||
| As these appear in every single module, let's just disable the warnings by marking the | |||
| two functions as __maybe_unused. | |||
| 
 | |||
| Signed-off-by: Arnd Bergmann <arnd@arndb.de> | |||
| Reviewed-by: Miroslav Benes <mbenes@suse.cz> | |||
| Acked-by: Rusty Russell <rusty@rustcorp.com.au> | |||
| Signed-off-by: Jessica Yu <jeyu@redhat.com> | |||
| Signed-off-by: Nathan Chancellor <natechancellor@gmail.com> | |||
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |||
| ---
 | |||
|  include/linux/module.h | 4 ++-- | |||
|  1 file changed, 2 insertions(+), 2 deletions(-) | |||
| 
 | |||
| (limited to 'include/linux/module.h') | |||
| 
 | |||
| diff --git a/include/linux/module.h b/include/linux/module.h
 | |||
| index c9f2f85017ad..dfe5c2e25ba1 100644
 | |||
| --- a/include/linux/module.h
 | |||
| +++ b/include/linux/module.h
 | |||
| @@ -125,13 +125,13 @@ extern void cleanup_module(void);
 | |||
|   | |||
|  /* Each module must use one module_init(). */ | |||
|  #define module_init(initfn)					\ | |||
| -	static inline initcall_t __inittest(void)		\
 | |||
| +	static inline initcall_t __maybe_unused __inittest(void)		\
 | |||
|  	{ return initfn; }					\ | |||
|  	int init_module(void) __attribute__((alias(#initfn))); | |||
|   | |||
|  /* This is only required if you want to be unloadable. */ | |||
|  #define module_exit(exitfn)					\ | |||
| -	static inline exitcall_t __exittest(void)		\
 | |||
| +	static inline exitcall_t __maybe_unused __exittest(void)		\
 | |||
|  	{ return exitfn; }					\ | |||
|  	void cleanup_module(void) __attribute__((alias(#exitfn))); | |||
|   | |||
| -- 
 | |||
| cgit 1.2-0.3.lf.el7 | |||
| 
 | |||
| @ -0,0 +1,84 @@ | |||
| From 170051d60cf08f9ae2cf296fb8410afdf56a911f Mon Sep 17 00:00:00 2001 | |||
| From: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> | |||
| Date: Sat, 19 Jan 2019 20:59:34 +0100 | |||
| Subject: include/linux/module.h: copy __init/__exit attrs to | |||
|  init/cleanup_module | |||
| 
 | |||
| [ Upstream commit a6e60d84989fa0e91db7f236eda40453b0e44afa ] | |||
| 
 | |||
| The upcoming GCC 9 release extends the -Wmissing-attributes warnings | |||
| (enabled by -Wall) to C and aliases: it warns when particular function | |||
| attributes are missing in the aliases but not in their target. | |||
| 
 | |||
| In particular, it triggers for all the init/cleanup_module | |||
| aliases in the kernel (defined by the module_init/exit macros), | |||
| ending up being very noisy. | |||
| 
 | |||
| These aliases point to the __init/__exit functions of a module, | |||
| which are defined as __cold (among other attributes). However, | |||
| the aliases themselves do not have the __cold attribute. | |||
| 
 | |||
| Since the compiler behaves differently when compiling a __cold | |||
| function as well as when compiling paths leading to calls | |||
| to __cold functions, the warning is trying to point out | |||
| the possibly-forgotten attribute in the alias. | |||
| 
 | |||
| In order to keep the warning enabled, we decided to silence | |||
| this case. Ideally, we would mark the aliases directly | |||
| as __init/__exit. However, there are currently around 132 modules | |||
| in the kernel which are missing __init/__exit in their init/cleanup | |||
| functions (either because they are missing, or for other reasons, | |||
| e.g. the functions being called from somewhere else); and | |||
| a section mismatch is a hard error. | |||
| 
 | |||
| A conservative alternative was to mark the aliases as __cold only. | |||
| However, since we would like to eventually enforce __init/__exit | |||
| to be always marked,  we chose to use the new __copy function | |||
| attribute (introduced by GCC 9 as well to deal with this). | |||
| With it, we copy the attributes used by the target functions | |||
| into the aliases. This way, functions that were not marked | |||
| as __init/__exit won't have their aliases marked either, | |||
| and therefore there won't be a section mismatch. | |||
| 
 | |||
| Note that the warning would go away marking either the extern | |||
| declaration, the definition, or both. However, we only mark | |||
| the definition of the alias, since we do not want callers | |||
| (which only see the declaration) to be compiled as if the function | |||
| was __cold (and therefore the paths leading to those calls | |||
| would be assumed to be unlikely). | |||
| 
 | |||
| Link: https://lore.kernel.org/lkml/20190123173707.GA16603@gmail.com/ | |||
| Link: https://lore.kernel.org/lkml/20190206175627.GA20399@gmail.com/ | |||
| Suggested-by: Martin Sebor <msebor@gcc.gnu.org> | |||
| Acked-by: Jessica Yu <jeyu@kernel.org> | |||
| Signed-off-by: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> | |||
| Signed-off-by: Sasha Levin <sashal@kernel.org> | |||
| ---
 | |||
|  include/linux/module.h | 4 ++-- | |||
|  1 file changed, 2 insertions(+), 2 deletions(-) | |||
| 
 | |||
| (limited to 'include/linux/module.h') | |||
| 
 | |||
| diff --git a/include/linux/module.h b/include/linux/module.h
 | |||
| index dfe5c2e25ba1..d237d0574179 100644
 | |||
| --- a/include/linux/module.h
 | |||
| +++ b/include/linux/module.h
 | |||
| @@ -127,13 +127,13 @@ extern void cleanup_module(void);
 | |||
|  #define module_init(initfn)					\ | |||
|  	static inline initcall_t __maybe_unused __inittest(void)		\ | |||
|  	{ return initfn; }					\ | |||
| -	int init_module(void) __attribute__((alias(#initfn)));
 | |||
| +	int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));
 | |||
|   | |||
|  /* This is only required if you want to be unloadable. */ | |||
|  #define module_exit(exitfn)					\ | |||
|  	static inline exitcall_t __maybe_unused __exittest(void)		\ | |||
|  	{ return exitfn; }					\ | |||
| -	void cleanup_module(void) __attribute__((alias(#exitfn)));
 | |||
| +	void cleanup_module(void) __copy(exitfn) __attribute__((alias(#exitfn)));
 | |||
|   | |||
|  #endif | |||
|   | |||
| -- 
 | |||
| cgit 1.2-0.3.lf.el7 | |||
| 
 | |||
| @ -0,0 +1,51 @@ | |||
| From edc966de8725f9186cc9358214da89d335f0e0bd Mon Sep 17 00:00:00 2001 | |||
| From: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> | |||
| Date: Fri, 2 Aug 2019 12:37:56 +0200 | |||
| Subject: Backport minimal compiler_attributes.h to support GCC 9 | |||
| 
 | |||
| This adds support for __copy to v4.9.y so that we can use it in | |||
| init/exit_module to avoid -Werror=missing-attributes errors on GCC 9. | |||
| 
 | |||
| Link: https://lore.kernel.org/lkml/259986242.BvXPX32bHu@devpool35/ | |||
| Cc: <stable@vger.kernel.org> | |||
| Suggested-by: Rolf Eike Beer <eb@emlix.com> | |||
| Signed-off-by: Miguel Ojeda <miguel.ojeda.sandonis@gmail.com> | |||
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |||
| 
 | |||
| Signed-off-by: Sasha Levin <sashal@kernel.org> | |||
| ---
 | |||
|  include/linux/compiler.h | 16 ++++++++++++++++ | |||
|  1 file changed, 16 insertions(+) | |||
| 
 | |||
| (limited to 'include/linux') | |||
| 
 | |||
| diff --git a/include/linux/compiler.h b/include/linux/compiler.h
 | |||
| index ed772311ec1f..5508011cc0c7 100644
 | |||
| --- a/include/linux/compiler.h
 | |||
| +++ b/include/linux/compiler.h
 | |||
| @@ -52,6 +52,22 @@ extern void __chk_io_ptr(const volatile void __iomem *);
 | |||
|   | |||
|  #ifdef __KERNEL__ | |||
|   | |||
| +/*
 | |||
| + * Minimal backport of compiler_attributes.h to add support for __copy
 | |||
| + * to v4.9.y so that we can use it in init/exit_module to avoid
 | |||
| + * -Werror=missing-attributes errors on GCC 9.
 | |||
| + */
 | |||
| +#ifndef __has_attribute
 | |||
| +# define __has_attribute(x) __GCC4_has_attribute_##x
 | |||
| +# define __GCC4_has_attribute___copy__                0
 | |||
| +#endif
 | |||
| +
 | |||
| +#if __has_attribute(__copy__)
 | |||
| +# define __copy(symbol)                 __attribute__((__copy__(symbol)))
 | |||
| +#else
 | |||
| +# define __copy(symbol)
 | |||
| +#endif
 | |||
| +
 | |||
|  #ifdef __GNUC__ | |||
|  #include <linux/compiler-gcc.h> | |||
|  #endif | |||
| -- 
 | |||
| cgit 1.2-0.3.lf.el7 | |||
| 
 | |||
| @ -0,0 +1,33 @@ | |||
| From 07d45a42fa21b54d83e563565699d25bde9f8cbe Mon Sep 17 00:00:00 2001 | |||
| From: Olli Salonen <olli.salonen@iki.fi> | |||
| Date: Sun, 30 Jul 2017 08:34:48 -0400 | |||
| Subject: media: mn88472: reset stream ID reg if no PLP given | |||
| 
 | |||
| If the PLP given is NO_STREAM_ID_FILTER (~0u) don't try to set that into the PLP register. Set PLP to 0 instead. | |||
| 
 | |||
| Signed-off-by: Olli Salonen <olli.salonen@iki.fi> | |||
| Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com> | |||
| ---
 | |||
|  drivers/media/dvb-frontends/mn88472.c | 4 +++- | |||
|  1 file changed, 3 insertions(+), 1 deletion(-) | |||
| 
 | |||
| (limited to 'drivers/media/dvb-frontends/mn88472.c') | |||
| 
 | |||
| diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c
 | |||
| index f6938f9607ac..5e8fd63832e9 100644
 | |||
| --- a/drivers/staging/media/mn88472/mn88472.c
 | |||
| +++ b/drivers/staging/media/mn88472/mn88472.c
 | |||
| @@ -255,7 +255,9 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
 | |||
|  		ret = regmap_write(dev->regmap[1], 0xf6, 0x05); | |||
|  		if (ret) | |||
|  			goto err; | |||
| -		ret = regmap_write(dev->regmap[2], 0x32, c->stream_id);
 | |||
| +		ret = regmap_write(dev->regmap[2], 0x32,
 | |||
| +				(c->stream_id == NO_STREAM_ID_FILTER) ? 0 :
 | |||
| +				c->stream_id );
 | |||
|  		if (ret) | |||
|  			goto err; | |||
|  		break; | |||
| -- 
 | |||
| cgit 1.2.3-1.el7 | |||
| 
 | |||
| @ -1,11 +0,0 @@ | |||
| --- a/net/wireless/scan.c
 | |||
| +++ b/net/wireless/scan.c
 | |||
| @@ -56,7 +56,7 @@
 | |||
|   * also linked into the probe response struct. | |||
|   */ | |||
|   | |||
| -#define IEEE80211_SCAN_RESULT_EXPIRE	(7 * HZ)
 | |||
| +#define IEEE80211_SCAN_RESULT_EXPIRE	(30 * HZ)
 | |||
|   | |||
|  static void bss_free(struct cfg80211_internal_bss *bss) | |||
|  { | |||
					Loading…
					
					
				
		Reference in new issue