cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dvbsky.c (22545B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Driver for DVBSky USB2.0 receiver
      4 *
      5 * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
      6 */
      7
      8#include "dvb_usb.h"
      9#include "m88ds3103.h"
     10#include "ts2020.h"
     11#include "sp2.h"
     12#include "si2168.h"
     13#include "si2157.h"
     14
     15#define DVBSKY_MSG_DELAY	0/*2000*/
     16#define DVBSKY_BUF_LEN	64
     17
     18static int dvb_usb_dvbsky_disable_rc;
     19module_param_named(disable_rc, dvb_usb_dvbsky_disable_rc, int, 0644);
     20MODULE_PARM_DESC(disable_rc, "Disable inbuilt IR receiver.");
     21
     22DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
     23
     24struct dvbsky_state {
     25	u8 ibuf[DVBSKY_BUF_LEN];
     26	u8 obuf[DVBSKY_BUF_LEN];
     27	u8 last_lock;
     28	struct i2c_client *i2c_client_demod;
     29	struct i2c_client *i2c_client_tuner;
     30	struct i2c_client *i2c_client_ci;
     31
     32	/* fe hook functions*/
     33	int (*fe_set_voltage)(struct dvb_frontend *fe,
     34		enum fe_sec_voltage voltage);
     35	int (*fe_read_status)(struct dvb_frontend *fe,
     36		enum fe_status *status);
     37};
     38
     39static int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
     40		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
     41{
     42	int ret;
     43	struct dvbsky_state *state = d_to_priv(d);
     44
     45	mutex_lock(&d->usb_mutex);
     46	if (wlen != 0)
     47		memcpy(state->obuf, wbuf, wlen);
     48
     49	ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
     50			state->ibuf, rlen);
     51
     52	if (!ret && (rlen != 0))
     53		memcpy(rbuf, state->ibuf, rlen);
     54
     55	mutex_unlock(&d->usb_mutex);
     56	return ret;
     57}
     58
     59static int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
     60{
     61	struct dvbsky_state *state = d_to_priv(d);
     62	static const u8 obuf_pre[3] = { 0x37, 0, 0 };
     63	static const u8 obuf_post[3] = { 0x36, 3, 0 };
     64	int ret;
     65
     66	mutex_lock(&d->usb_mutex);
     67	memcpy(state->obuf, obuf_pre, 3);
     68	ret = dvb_usbv2_generic_write_locked(d, state->obuf, 3);
     69	if (!ret && onoff) {
     70		msleep(20);
     71		memcpy(state->obuf, obuf_post, 3);
     72		ret = dvb_usbv2_generic_write_locked(d, state->obuf, 3);
     73	}
     74	mutex_unlock(&d->usb_mutex);
     75	return ret;
     76}
     77
     78static int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
     79{
     80	struct dvb_usb_device *d = fe_to_d(fe);
     81
     82	return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
     83}
     84
     85/* GPIO */
     86static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
     87{
     88	int ret;
     89	u8 obuf[3], ibuf[2];
     90
     91	obuf[0] = 0x0e;
     92	obuf[1] = gport;
     93	obuf[2] = value;
     94	ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
     95	return ret;
     96}
     97
     98/* I2C */
     99static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
    100	int num)
    101{
    102	struct dvb_usb_device *d = i2c_get_adapdata(adap);
    103	int ret = 0;
    104	u8 ibuf[64], obuf[64];
    105
    106	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
    107		return -EAGAIN;
    108
    109	if (num > 2) {
    110		dev_err(&d->udev->dev,
    111		"too many i2c messages[%d], max 2.", num);
    112		ret = -EOPNOTSUPP;
    113		goto i2c_error;
    114	}
    115
    116	if (num == 1) {
    117		if (msg[0].len > 60) {
    118			dev_err(&d->udev->dev,
    119			"too many i2c bytes[%d], max 60.",
    120			msg[0].len);
    121			ret = -EOPNOTSUPP;
    122			goto i2c_error;
    123		}
    124		if (msg[0].flags & I2C_M_RD) {
    125			/* single read */
    126			obuf[0] = 0x09;
    127			obuf[1] = 0;
    128			obuf[2] = msg[0].len;
    129			obuf[3] = msg[0].addr;
    130			ret = dvbsky_usb_generic_rw(d, obuf, 4,
    131					ibuf, msg[0].len + 1);
    132			if (!ret)
    133				memcpy(msg[0].buf, &ibuf[1], msg[0].len);
    134		} else {
    135			/* write */
    136			obuf[0] = 0x08;
    137			obuf[1] = msg[0].addr;
    138			obuf[2] = msg[0].len;
    139			memcpy(&obuf[3], msg[0].buf, msg[0].len);
    140			ret = dvbsky_usb_generic_rw(d, obuf,
    141					msg[0].len + 3, ibuf, 1);
    142		}
    143	} else {
    144		if ((msg[0].len > 60) || (msg[1].len > 60)) {
    145			dev_err(&d->udev->dev,
    146			"too many i2c bytes[w-%d][r-%d], max 60.",
    147			msg[0].len, msg[1].len);
    148			ret = -EOPNOTSUPP;
    149			goto i2c_error;
    150		}
    151		/* write then read */
    152		obuf[0] = 0x09;
    153		obuf[1] = msg[0].len;
    154		obuf[2] = msg[1].len;
    155		obuf[3] = msg[0].addr;
    156		memcpy(&obuf[4], msg[0].buf, msg[0].len);
    157		ret = dvbsky_usb_generic_rw(d, obuf,
    158			msg[0].len + 4, ibuf, msg[1].len + 1);
    159		if (!ret)
    160			memcpy(msg[1].buf, &ibuf[1], msg[1].len);
    161	}
    162i2c_error:
    163	mutex_unlock(&d->i2c_mutex);
    164	return (ret) ? ret : num;
    165}
    166
    167static u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
    168{
    169	return I2C_FUNC_I2C;
    170}
    171
    172static struct i2c_algorithm dvbsky_i2c_algo = {
    173	.master_xfer   = dvbsky_i2c_xfer,
    174	.functionality = dvbsky_i2c_func,
    175};
    176
    177#if IS_ENABLED(CONFIG_RC_CORE)
    178static int dvbsky_rc_query(struct dvb_usb_device *d)
    179{
    180	u32 code = 0xffff, scancode;
    181	u8 rc5_command, rc5_system;
    182	u8 obuf[2], ibuf[2], toggle;
    183	int ret;
    184
    185	obuf[0] = 0x10;
    186	ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
    187	if (ret == 0)
    188		code = (ibuf[0] << 8) | ibuf[1];
    189	if (code != 0xffff) {
    190		dev_dbg(&d->udev->dev, "rc code: %x\n", code);
    191		rc5_command = code & 0x3F;
    192		rc5_system = (code & 0x7C0) >> 6;
    193		toggle = (code & 0x800) ? 1 : 0;
    194		scancode = rc5_system << 8 | rc5_command;
    195		rc_keydown(d->rc_dev, RC_PROTO_RC5, scancode, toggle);
    196	}
    197	return 0;
    198}
    199
    200static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
    201{
    202	if (dvb_usb_dvbsky_disable_rc) {
    203		rc->map_name = NULL;
    204		return 0;
    205	}
    206
    207	rc->allowed_protos = RC_PROTO_BIT_RC5;
    208	rc->query          = dvbsky_rc_query;
    209	rc->interval       = 300;
    210	return 0;
    211}
    212#else
    213	#define dvbsky_get_rc_config NULL
    214#endif
    215
    216static int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
    217	enum fe_sec_voltage voltage)
    218{
    219	struct dvb_usb_device *d = fe_to_d(fe);
    220	struct dvbsky_state *state = d_to_priv(d);
    221	u8 value;
    222
    223	if (voltage == SEC_VOLTAGE_OFF)
    224		value = 0;
    225	else
    226		value = 1;
    227	dvbsky_gpio_ctrl(d, 0x80, value);
    228
    229	return state->fe_set_voltage(fe, voltage);
    230}
    231
    232static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
    233{
    234	struct dvb_usb_device *d = adap_to_d(adap);
    235	u8 obuf[] = { 0x1e, 0x00 };
    236	u8 ibuf[6] = { 0 };
    237	struct i2c_msg msg[] = {
    238		{
    239			.addr = 0x51,
    240			.flags = 0,
    241			.buf = obuf,
    242			.len = 2,
    243		}, {
    244			.addr = 0x51,
    245			.flags = I2C_M_RD,
    246			.buf = ibuf,
    247			.len = 6,
    248		}
    249	};
    250
    251	if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
    252		memcpy(mac, ibuf, 6);
    253
    254	return 0;
    255}
    256
    257static int dvbsky_usb_read_status(struct dvb_frontend *fe,
    258				  enum fe_status *status)
    259{
    260	struct dvb_usb_device *d = fe_to_d(fe);
    261	struct dvbsky_state *state = d_to_priv(d);
    262	int ret;
    263
    264	ret = state->fe_read_status(fe, status);
    265
    266	/* it need resync slave fifo when signal change from unlock to lock.*/
    267	if ((*status & FE_HAS_LOCK) && (!state->last_lock))
    268		dvbsky_stream_ctrl(d, 1);
    269
    270	state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
    271	return ret;
    272}
    273
    274static int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
    275{
    276	struct dvbsky_state *state = adap_to_priv(adap);
    277	struct dvb_usb_device *d = adap_to_d(adap);
    278	struct i2c_adapter *i2c_adapter;
    279	struct m88ds3103_platform_data m88ds3103_pdata = {};
    280	struct ts2020_config ts2020_config = {};
    281
    282	/* attach demod */
    283	m88ds3103_pdata.clk = 27000000;
    284	m88ds3103_pdata.i2c_wr_max = 33;
    285	m88ds3103_pdata.clk_out = 0;
    286	m88ds3103_pdata.ts_mode = M88DS3103_TS_CI;
    287	m88ds3103_pdata.ts_clk = 16000;
    288	m88ds3103_pdata.ts_clk_pol = 0;
    289	m88ds3103_pdata.agc = 0x99;
    290	m88ds3103_pdata.lnb_hv_pol = 1;
    291	m88ds3103_pdata.lnb_en_pol = 1;
    292
    293	state->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
    294						   &d->i2c_adap,
    295						   0x68, &m88ds3103_pdata);
    296	if (!state->i2c_client_demod)
    297		return -ENODEV;
    298
    299	adap->fe[0] = m88ds3103_pdata.get_dvb_frontend(state->i2c_client_demod);
    300	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(state->i2c_client_demod);
    301
    302	/* attach tuner */
    303	ts2020_config.fe = adap->fe[0];
    304	ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
    305
    306	state->i2c_client_tuner = dvb_module_probe("ts2020", NULL,
    307						   i2c_adapter,
    308						   0x60, &ts2020_config);
    309	if (!state->i2c_client_tuner) {
    310		dvb_module_release(state->i2c_client_demod);
    311		return -ENODEV;
    312	}
    313
    314	/* delegate signal strength measurement to tuner */
    315	adap->fe[0]->ops.read_signal_strength =
    316			adap->fe[0]->ops.tuner_ops.get_rf_strength;
    317
    318	/* hook fe: need to resync the slave fifo when signal locks. */
    319	state->fe_read_status = adap->fe[0]->ops.read_status;
    320	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
    321
    322	/* hook fe: LNB off/on is control by Cypress usb chip. */
    323	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
    324	adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
    325
    326	return 0;
    327}
    328
    329static int dvbsky_usb_ci_set_voltage(struct dvb_frontend *fe,
    330	enum fe_sec_voltage voltage)
    331{
    332	struct dvb_usb_device *d = fe_to_d(fe);
    333	struct dvbsky_state *state = d_to_priv(d);
    334	u8 value;
    335
    336	if (voltage == SEC_VOLTAGE_OFF)
    337		value = 0;
    338	else
    339		value = 1;
    340	dvbsky_gpio_ctrl(d, 0x00, value);
    341
    342	return state->fe_set_voltage(fe, voltage);
    343}
    344
    345static int dvbsky_ci_ctrl(void *priv, u8 read, int addr,
    346					u8 data, int *mem)
    347{
    348	struct dvb_usb_device *d = priv;
    349	int ret = 0;
    350	u8 command[4], respond[2], command_size, respond_size;
    351
    352	command[1] = (u8)((addr >> 8) & 0xff); /*high part of address*/
    353	command[2] = (u8)(addr & 0xff); /*low part of address*/
    354	if (read) {
    355		command[0] = 0x71;
    356		command_size = 3;
    357		respond_size = 2;
    358	} else {
    359		command[0] = 0x70;
    360		command[3] = data;
    361		command_size = 4;
    362		respond_size = 1;
    363	}
    364	ret = dvbsky_usb_generic_rw(d, command, command_size,
    365			respond, respond_size);
    366	if (ret)
    367		goto err;
    368	if (read)
    369		*mem = respond[1];
    370	return ret;
    371err:
    372	dev_err(&d->udev->dev, "ci control failed=%d\n", ret);
    373	return ret;
    374}
    375
    376static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
    377{
    378	struct dvbsky_state *state = adap_to_priv(adap);
    379	struct dvb_usb_device *d = adap_to_d(adap);
    380	struct i2c_adapter *i2c_adapter;
    381	struct m88ds3103_platform_data m88ds3103_pdata = {};
    382	struct ts2020_config ts2020_config = {};
    383	struct sp2_config sp2_config = {};
    384
    385	/* attach demod */
    386	m88ds3103_pdata.clk = 27000000;
    387	m88ds3103_pdata.i2c_wr_max = 33;
    388	m88ds3103_pdata.clk_out = 0;
    389	m88ds3103_pdata.ts_mode = M88DS3103_TS_CI;
    390	m88ds3103_pdata.ts_clk = 10000;
    391	m88ds3103_pdata.ts_clk_pol = 1;
    392	m88ds3103_pdata.agc = 0x99;
    393	m88ds3103_pdata.lnb_hv_pol = 0;
    394	m88ds3103_pdata.lnb_en_pol = 1;
    395
    396	state->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
    397						   &d->i2c_adap,
    398						   0x68, &m88ds3103_pdata);
    399	if (!state->i2c_client_demod)
    400		return -ENODEV;
    401
    402	adap->fe[0] = m88ds3103_pdata.get_dvb_frontend(state->i2c_client_demod);
    403	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(state->i2c_client_demod);
    404
    405	/* attach tuner */
    406	ts2020_config.fe = adap->fe[0];
    407	ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
    408
    409	state->i2c_client_tuner = dvb_module_probe("ts2020", NULL,
    410						   i2c_adapter,
    411						   0x60, &ts2020_config);
    412	if (!state->i2c_client_tuner) {
    413		dvb_module_release(state->i2c_client_demod);
    414		return -ENODEV;
    415	}
    416
    417	/* attach ci controller */
    418	sp2_config.dvb_adap = &adap->dvb_adap;
    419	sp2_config.priv = d;
    420	sp2_config.ci_control = dvbsky_ci_ctrl;
    421
    422	state->i2c_client_ci = dvb_module_probe("sp2", NULL,
    423						&d->i2c_adap,
    424						0x40, &sp2_config);
    425
    426	if (!state->i2c_client_ci) {
    427		dvb_module_release(state->i2c_client_tuner);
    428		dvb_module_release(state->i2c_client_demod);
    429		return -ENODEV;
    430	}
    431
    432	/* delegate signal strength measurement to tuner */
    433	adap->fe[0]->ops.read_signal_strength =
    434			adap->fe[0]->ops.tuner_ops.get_rf_strength;
    435
    436	/* hook fe: need to resync the slave fifo when signal locks. */
    437	state->fe_read_status = adap->fe[0]->ops.read_status;
    438	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
    439
    440	/* hook fe: LNB off/on is control by Cypress usb chip. */
    441	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
    442	adap->fe[0]->ops.set_voltage = dvbsky_usb_ci_set_voltage;
    443
    444	return 0;
    445}
    446
    447static int dvbsky_t680c_attach(struct dvb_usb_adapter *adap)
    448{
    449	struct dvbsky_state *state = adap_to_priv(adap);
    450	struct dvb_usb_device *d = adap_to_d(adap);
    451	struct i2c_adapter *i2c_adapter;
    452	struct si2168_config si2168_config = {};
    453	struct si2157_config si2157_config = {};
    454	struct sp2_config sp2_config = {};
    455
    456	/* attach demod */
    457	si2168_config.i2c_adapter = &i2c_adapter;
    458	si2168_config.fe = &adap->fe[0];
    459	si2168_config.ts_mode = SI2168_TS_PARALLEL;
    460
    461	state->i2c_client_demod = dvb_module_probe("si2168", NULL,
    462						   &d->i2c_adap,
    463						   0x64, &si2168_config);
    464	if (!state->i2c_client_demod)
    465		return -ENODEV;
    466
    467	/* attach tuner */
    468	si2157_config.fe = adap->fe[0];
    469	si2157_config.if_port = 1;
    470
    471	state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
    472						   i2c_adapter,
    473						   0x60, &si2157_config);
    474	if (!state->i2c_client_tuner) {
    475		dvb_module_release(state->i2c_client_demod);
    476		return -ENODEV;
    477	}
    478
    479	/* attach ci controller */
    480	sp2_config.dvb_adap = &adap->dvb_adap;
    481	sp2_config.priv = d;
    482	sp2_config.ci_control = dvbsky_ci_ctrl;
    483
    484	state->i2c_client_ci = dvb_module_probe("sp2", NULL,
    485						&d->i2c_adap,
    486						0x40, &sp2_config);
    487
    488	if (!state->i2c_client_ci) {
    489		dvb_module_release(state->i2c_client_tuner);
    490		dvb_module_release(state->i2c_client_demod);
    491		return -ENODEV;
    492	}
    493
    494	return 0;
    495}
    496
    497static int dvbsky_t330_attach(struct dvb_usb_adapter *adap)
    498{
    499	struct dvbsky_state *state = adap_to_priv(adap);
    500	struct dvb_usb_device *d = adap_to_d(adap);
    501	struct i2c_adapter *i2c_adapter;
    502	struct si2168_config si2168_config = {};
    503	struct si2157_config si2157_config = {};
    504
    505	/* attach demod */
    506	si2168_config.i2c_adapter = &i2c_adapter;
    507	si2168_config.fe = &adap->fe[0];
    508	si2168_config.ts_mode = SI2168_TS_PARALLEL;
    509	si2168_config.ts_clock_gapped = true;
    510
    511	state->i2c_client_demod = dvb_module_probe("si2168", NULL,
    512						   &d->i2c_adap,
    513						   0x64, &si2168_config);
    514	if (!state->i2c_client_demod)
    515		return -ENODEV;
    516
    517	/* attach tuner */
    518	si2157_config.fe = adap->fe[0];
    519	si2157_config.if_port = 1;
    520
    521	state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
    522						   i2c_adapter,
    523						   0x60, &si2157_config);
    524	if (!state->i2c_client_tuner) {
    525		dvb_module_release(state->i2c_client_demod);
    526		return -ENODEV;
    527	}
    528
    529	return 0;
    530}
    531
    532static int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap)
    533{
    534	struct dvbsky_state *state = adap_to_priv(adap);
    535	struct dvb_usb_device *d = adap_to_d(adap);
    536	struct i2c_adapter *i2c_adapter;
    537	struct si2168_config si2168_config = {};
    538	struct si2157_config si2157_config = {};
    539
    540	/* attach demod */
    541	si2168_config.i2c_adapter = &i2c_adapter;
    542	si2168_config.fe = &adap->fe[0];
    543	si2168_config.ts_mode = SI2168_TS_PARALLEL;
    544	if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2 ||
    545	    le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2_LITE ||
    546	    le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A)
    547		si2168_config.ts_mode |= SI2168_TS_CLK_MANUAL;
    548	si2168_config.ts_clock_inv = 1;
    549
    550	state->i2c_client_demod = dvb_module_probe("si2168", NULL,
    551						   &d->i2c_adap,
    552						   0x64, &si2168_config);
    553	if (!state->i2c_client_demod)
    554		return -ENODEV;
    555
    556	/* attach tuner */
    557	si2157_config.fe = adap->fe[0];
    558	if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230) {
    559		si2157_config.if_port = 1;
    560		state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
    561							   i2c_adapter,
    562							   0x60,
    563							   &si2157_config);
    564	} else {
    565		si2157_config.if_port = 0;
    566		state->i2c_client_tuner = dvb_module_probe("si2157", "si2141",
    567							   i2c_adapter,
    568							   0x60,
    569							   &si2157_config);
    570	}
    571	if (!state->i2c_client_tuner) {
    572		dvb_module_release(state->i2c_client_demod);
    573		return -ENODEV;
    574	}
    575
    576	return 0;
    577}
    578
    579
    580static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
    581{
    582	if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230A) {
    583		dvbsky_gpio_ctrl(d, 0x87, 0);
    584		msleep(20);
    585		dvbsky_gpio_ctrl(d, 0x86, 1);
    586		dvbsky_gpio_ctrl(d, 0x80, 0);
    587		msleep(100);
    588		dvbsky_gpio_ctrl(d, 0x80, 1);
    589		msleep(50);
    590	} else {
    591		dvbsky_gpio_ctrl(d, 0x04, 1);
    592		msleep(20);
    593		dvbsky_gpio_ctrl(d, 0x83, 0);
    594		dvbsky_gpio_ctrl(d, 0xc0, 1);
    595		msleep(100);
    596		dvbsky_gpio_ctrl(d, 0x83, 1);
    597		dvbsky_gpio_ctrl(d, 0xc0, 0);
    598		msleep(50);
    599	}
    600	return WARM;
    601}
    602
    603static int dvbsky_init(struct dvb_usb_device *d)
    604{
    605	struct dvbsky_state *state = d_to_priv(d);
    606	state->last_lock = 0;
    607	return 0;
    608}
    609
    610static int dvbsky_frontend_detach(struct dvb_usb_adapter *adap)
    611{
    612	struct dvb_usb_device *d = adap_to_d(adap);
    613	struct dvbsky_state *state = d_to_priv(d);
    614
    615	dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
    616
    617	dvb_module_release(state->i2c_client_tuner);
    618	dvb_module_release(state->i2c_client_demod);
    619	dvb_module_release(state->i2c_client_ci);
    620
    621	return 0;
    622}
    623
    624/* DVB USB Driver stuff */
    625static struct dvb_usb_device_properties dvbsky_s960_props = {
    626	.driver_name = KBUILD_MODNAME,
    627	.owner = THIS_MODULE,
    628	.adapter_nr = adapter_nr,
    629	.size_of_priv = sizeof(struct dvbsky_state),
    630
    631	.generic_bulk_ctrl_endpoint = 0x01,
    632	.generic_bulk_ctrl_endpoint_response = 0x81,
    633	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
    634
    635	.i2c_algo         = &dvbsky_i2c_algo,
    636	.frontend_attach  = dvbsky_s960_attach,
    637	.frontend_detach  = dvbsky_frontend_detach,
    638	.init             = dvbsky_init,
    639	.get_rc_config    = dvbsky_get_rc_config,
    640	.streaming_ctrl   = dvbsky_streaming_ctrl,
    641	.identify_state	  = dvbsky_identify_state,
    642	.read_mac_address = dvbsky_read_mac_addr,
    643
    644	.num_adapters = 1,
    645	.adapter = {
    646		{
    647			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
    648		}
    649	}
    650};
    651
    652static struct dvb_usb_device_properties dvbsky_s960c_props = {
    653	.driver_name = KBUILD_MODNAME,
    654	.owner = THIS_MODULE,
    655	.adapter_nr = adapter_nr,
    656	.size_of_priv = sizeof(struct dvbsky_state),
    657
    658	.generic_bulk_ctrl_endpoint = 0x01,
    659	.generic_bulk_ctrl_endpoint_response = 0x81,
    660	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
    661
    662	.i2c_algo         = &dvbsky_i2c_algo,
    663	.frontend_attach  = dvbsky_s960c_attach,
    664	.frontend_detach  = dvbsky_frontend_detach,
    665	.init             = dvbsky_init,
    666	.get_rc_config    = dvbsky_get_rc_config,
    667	.streaming_ctrl   = dvbsky_streaming_ctrl,
    668	.identify_state	  = dvbsky_identify_state,
    669	.read_mac_address = dvbsky_read_mac_addr,
    670
    671	.num_adapters = 1,
    672	.adapter = {
    673		{
    674			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
    675		}
    676	}
    677};
    678
    679static struct dvb_usb_device_properties dvbsky_t680c_props = {
    680	.driver_name = KBUILD_MODNAME,
    681	.owner = THIS_MODULE,
    682	.adapter_nr = adapter_nr,
    683	.size_of_priv = sizeof(struct dvbsky_state),
    684
    685	.generic_bulk_ctrl_endpoint = 0x01,
    686	.generic_bulk_ctrl_endpoint_response = 0x81,
    687	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
    688
    689	.i2c_algo         = &dvbsky_i2c_algo,
    690	.frontend_attach  = dvbsky_t680c_attach,
    691	.frontend_detach  = dvbsky_frontend_detach,
    692	.init             = dvbsky_init,
    693	.get_rc_config    = dvbsky_get_rc_config,
    694	.streaming_ctrl   = dvbsky_streaming_ctrl,
    695	.identify_state	  = dvbsky_identify_state,
    696	.read_mac_address = dvbsky_read_mac_addr,
    697
    698	.num_adapters = 1,
    699	.adapter = {
    700		{
    701			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
    702		}
    703	}
    704};
    705
    706static struct dvb_usb_device_properties dvbsky_t330_props = {
    707	.driver_name = KBUILD_MODNAME,
    708	.owner = THIS_MODULE,
    709	.adapter_nr = adapter_nr,
    710	.size_of_priv = sizeof(struct dvbsky_state),
    711
    712	.generic_bulk_ctrl_endpoint = 0x01,
    713	.generic_bulk_ctrl_endpoint_response = 0x81,
    714	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
    715
    716	.i2c_algo         = &dvbsky_i2c_algo,
    717	.frontend_attach  = dvbsky_t330_attach,
    718	.frontend_detach  = dvbsky_frontend_detach,
    719	.init             = dvbsky_init,
    720	.get_rc_config    = dvbsky_get_rc_config,
    721	.streaming_ctrl   = dvbsky_streaming_ctrl,
    722	.identify_state	  = dvbsky_identify_state,
    723	.read_mac_address = dvbsky_read_mac_addr,
    724
    725	.num_adapters = 1,
    726	.adapter = {
    727		{
    728			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
    729		}
    730	}
    731};
    732
    733static struct dvb_usb_device_properties mygica_t230c_props = {
    734	.driver_name = KBUILD_MODNAME,
    735	.owner = THIS_MODULE,
    736	.adapter_nr = adapter_nr,
    737	.size_of_priv = sizeof(struct dvbsky_state),
    738
    739	.generic_bulk_ctrl_endpoint = 0x01,
    740	.generic_bulk_ctrl_endpoint_response = 0x81,
    741	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
    742
    743	.i2c_algo         = &dvbsky_i2c_algo,
    744	.frontend_attach  = dvbsky_mygica_t230c_attach,
    745	.frontend_detach  = dvbsky_frontend_detach,
    746	.init             = dvbsky_init,
    747	.get_rc_config    = dvbsky_get_rc_config,
    748	.streaming_ctrl   = dvbsky_streaming_ctrl,
    749	.identify_state	  = dvbsky_identify_state,
    750
    751	.num_adapters = 1,
    752	.adapter = {
    753		{
    754			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
    755		}
    756	}
    757};
    758
    759static const struct usb_device_id dvbsky_id_table[] = {
    760	{ DVB_USB_DEVICE(0x0572, 0x6831,
    761		&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
    762	{ DVB_USB_DEVICE(0x0572, 0x960c,
    763		&dvbsky_s960c_props, "DVBSky S960CI", RC_MAP_DVBSKY) },
    764	{ DVB_USB_DEVICE(0x0572, 0x680c,
    765		&dvbsky_t680c_props, "DVBSky T680CI", RC_MAP_DVBSKY) },
    766	{ DVB_USB_DEVICE(0x0572, 0x0320,
    767		&dvbsky_t330_props, "DVBSky T330", RC_MAP_DVBSKY) },
    768	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
    769		USB_PID_TECHNOTREND_TVSTICK_CT2_4400,
    770		&dvbsky_t330_props, "TechnoTrend TVStick CT2-4400",
    771		RC_MAP_TT_1500) },
    772	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
    773		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI,
    774		&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI",
    775		RC_MAP_TT_1500) },
    776	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
    777		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2,
    778		&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI v1.1",
    779		RC_MAP_TT_1500) },
    780	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
    781		USB_PID_TECHNOTREND_CONNECT_S2_4650_CI,
    782		&dvbsky_s960c_props, "TechnoTrend TT-connect S2-4650 CI",
    783		RC_MAP_TT_1500) },
    784	{ DVB_USB_DEVICE(USB_VID_TERRATEC,
    785		USB_PID_TERRATEC_H7_3,
    786		&dvbsky_t680c_props, "Terratec H7 Rev.4",
    787		RC_MAP_TT_1500) },
    788	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4,
    789		&dvbsky_s960_props, "Terratec Cinergy S2 Rev.4",
    790		RC_MAP_DVBSKY) },
    791	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230,
    792		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230",
    793		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
    794	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C,
    795		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C",
    796		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
    797	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C_LITE,
    798		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C Lite",
    799		NULL) },
    800	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2,
    801		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2",
    802		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
    803	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2_LITE,
    804		 &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2  Lite",
    805		 NULL) },
    806	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230A,
    807		 &mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230A",
    808		 NULL) },
    809	{ }
    810};
    811MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
    812
    813static struct usb_driver dvbsky_usb_driver = {
    814	.name = KBUILD_MODNAME,
    815	.id_table = dvbsky_id_table,
    816	.probe = dvb_usbv2_probe,
    817	.disconnect = dvb_usbv2_disconnect,
    818	.suspend = dvb_usbv2_suspend,
    819	.resume = dvb_usbv2_resume,
    820	.reset_resume = dvb_usbv2_reset_resume,
    821	.no_dynamic_id = 1,
    822	.soft_unbind = 1,
    823};
    824
    825module_usb_driver(dvbsky_usb_driver);
    826
    827MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
    828MODULE_DESCRIPTION("Driver for DVBSky USB");
    829MODULE_LICENSE("GPL");