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

technisat-usb2.c (20077B)


      1/*
      2 * Linux driver for Technisat DVB-S/S2 USB 2.0 device
      3 *
      4 * Copyright (C) 2010 Patrick Boettcher,
      5 *                    Kernel Labs Inc. PO Box 745, St James, NY 11780
      6 *
      7 * Development was sponsored by Technisat Digital UK Limited, whose
      8 * registered office is Witan Gate House 500 - 600 Witan Gate West,
      9 * Milton Keynes, MK9 1SH
     10 *
     11 * This program is free software; you can redistribute it and/or
     12 * modify it under the terms of the GNU General Public License as
     13 * published by the Free Software Foundation; either version 2 of the
     14 * License, or (at your option) any later version.
     15 *
     16 *
     17 * THIS PROGRAM IS PROVIDED "AS IS" AND BOTH THE COPYRIGHT HOLDER AND
     18 * TECHNISAT DIGITAL UK LTD DISCLAIM ALL WARRANTIES WITH REGARD TO
     19 * THIS PROGRAM INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY OR
     20 * FITNESS FOR A PARTICULAR PURPOSE.  NEITHER THE COPYRIGHT HOLDER
     21 * NOR TECHNISAT DIGITAL UK LIMITED SHALL BE LIABLE FOR ANY SPECIAL,
     22 * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
     23 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     24 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
     25 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS PROGRAM. See the
     26 * GNU General Public License for more details.
     27 */
     28
     29#define DVB_USB_LOG_PREFIX "technisat-usb2"
     30#include "dvb-usb.h"
     31
     32#include "stv6110x.h"
     33#include "stv090x.h"
     34
     35/* module parameters */
     36DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
     37
     38static int debug;
     39module_param(debug, int, 0644);
     40MODULE_PARM_DESC(debug,
     41		"set debugging level (bit-mask: 1=info,2=eeprom,4=i2c,8=rc)." \
     42		DVB_USB_DEBUG_STATUS);
     43
     44/* disables all LED control command and
     45 * also does not start the signal polling thread */
     46static int disable_led_control;
     47module_param(disable_led_control, int, 0444);
     48MODULE_PARM_DESC(disable_led_control,
     49		"disable LED control of the device (default: 0 - LED control is active).");
     50
     51/* device private data */
     52struct technisat_usb2_state {
     53	struct dvb_usb_device *dev;
     54	struct delayed_work green_led_work;
     55	u8 power_state;
     56
     57	u16 last_scan_code;
     58
     59	u8 buf[64];
     60};
     61
     62/* debug print helpers */
     63#define deb_info(args...)    dprintk(debug, 0x01, args)
     64#define deb_eeprom(args...)  dprintk(debug, 0x02, args)
     65#define deb_i2c(args...)     dprintk(debug, 0x04, args)
     66#define deb_rc(args...)      dprintk(debug, 0x08, args)
     67
     68/* vendor requests */
     69#define SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST 0xB3
     70#define SET_FRONT_END_RESET_VENDOR_REQUEST         0xB4
     71#define GET_VERSION_INFO_VENDOR_REQUEST            0xB5
     72#define SET_GREEN_LED_VENDOR_REQUEST               0xB6
     73#define SET_RED_LED_VENDOR_REQUEST                 0xB7
     74#define GET_IR_DATA_VENDOR_REQUEST                 0xB8
     75#define SET_LED_TIMER_DIVIDER_VENDOR_REQUEST       0xB9
     76#define SET_USB_REENUMERATION                      0xBA
     77
     78/* i2c-access methods */
     79#define I2C_SPEED_100KHZ_BIT 0x40
     80
     81#define I2C_STATUS_NAK 7
     82#define I2C_STATUS_OK 8
     83
     84static int technisat_usb2_i2c_access(struct usb_device *udev,
     85		u8 device_addr, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
     86{
     87	u8 *b;
     88	int ret, actual_length;
     89
     90	b = kmalloc(64, GFP_KERNEL);
     91	if (!b)
     92		return -ENOMEM;
     93
     94	deb_i2c("i2c-access: %02x, tx: ", device_addr);
     95	debug_dump(tx, txlen, deb_i2c);
     96	deb_i2c(" ");
     97
     98	if (txlen > 62) {
     99		err("i2c TX buffer can't exceed 62 bytes (dev 0x%02x)",
    100				device_addr);
    101		txlen = 62;
    102	}
    103	if (rxlen > 62) {
    104		err("i2c RX buffer can't exceed 62 bytes (dev 0x%02x)",
    105				device_addr);
    106		rxlen = 62;
    107	}
    108
    109	b[0] = I2C_SPEED_100KHZ_BIT;
    110	b[1] = device_addr << 1;
    111
    112	if (rx != NULL) {
    113		b[0] |= rxlen;
    114		b[1] |= 1;
    115	}
    116
    117	memcpy(&b[2], tx, txlen);
    118	ret = usb_bulk_msg(udev,
    119			usb_sndbulkpipe(udev, 0x01),
    120			b, 2 + txlen,
    121			NULL, 1000);
    122
    123	if (ret < 0) {
    124		err("i2c-error: out failed %02x = %d", device_addr, ret);
    125		goto err;
    126	}
    127
    128	ret = usb_bulk_msg(udev,
    129			usb_rcvbulkpipe(udev, 0x01),
    130			b, 64, &actual_length, 1000);
    131	if (ret < 0) {
    132		err("i2c-error: in failed %02x = %d", device_addr, ret);
    133		goto err;
    134	}
    135
    136	if (b[0] != I2C_STATUS_OK) {
    137		err("i2c-error: %02x = %d", device_addr, b[0]);
    138		/* handle tuner-i2c-nak */
    139		if (!(b[0] == I2C_STATUS_NAK &&
    140				device_addr == 0x60
    141				/* && device_is_technisat_usb2 */))
    142			goto err;
    143	}
    144
    145	deb_i2c("status: %d, ", b[0]);
    146
    147	if (rx != NULL) {
    148		memcpy(rx, &b[2], rxlen);
    149
    150		deb_i2c("rx (%d): ", rxlen);
    151		debug_dump(rx, rxlen, deb_i2c);
    152	}
    153
    154	deb_i2c("\n");
    155
    156err:
    157	kfree(b);
    158	return ret;
    159}
    160
    161static int technisat_usb2_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
    162				int num)
    163{
    164	int ret = 0, i;
    165	struct dvb_usb_device *d = i2c_get_adapdata(adap);
    166
    167	/* Ensure nobody else hits the i2c bus while we're sending our
    168	   sequence of messages, (such as the remote control thread) */
    169	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
    170		return -EAGAIN;
    171
    172	for (i = 0; i < num; i++) {
    173		if (i+1 < num && msg[i+1].flags & I2C_M_RD) {
    174			ret = technisat_usb2_i2c_access(d->udev, msg[i+1].addr,
    175						msg[i].buf, msg[i].len,
    176						msg[i+1].buf, msg[i+1].len);
    177			if (ret != 0)
    178				break;
    179			i++;
    180		} else {
    181			ret = technisat_usb2_i2c_access(d->udev, msg[i].addr,
    182						msg[i].buf, msg[i].len,
    183						NULL, 0);
    184			if (ret != 0)
    185				break;
    186		}
    187	}
    188
    189	if (ret == 0)
    190		ret = i;
    191
    192	mutex_unlock(&d->i2c_mutex);
    193
    194	return ret;
    195}
    196
    197static u32 technisat_usb2_i2c_func(struct i2c_adapter *adapter)
    198{
    199	return I2C_FUNC_I2C;
    200}
    201
    202static struct i2c_algorithm technisat_usb2_i2c_algo = {
    203	.master_xfer   = technisat_usb2_i2c_xfer,
    204	.functionality = technisat_usb2_i2c_func,
    205};
    206
    207#if 0
    208static void technisat_usb2_frontend_reset(struct usb_device *udev)
    209{
    210	usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
    211			SET_FRONT_END_RESET_VENDOR_REQUEST,
    212			USB_TYPE_VENDOR | USB_DIR_OUT,
    213			10, 0,
    214			NULL, 0, 500);
    215}
    216#endif
    217
    218/* LED control */
    219enum technisat_usb2_led_state {
    220	TECH_LED_OFF,
    221	TECH_LED_BLINK,
    222	TECH_LED_ON,
    223	TECH_LED_UNDEFINED
    224};
    225
    226static int technisat_usb2_set_led(struct dvb_usb_device *d, int red,
    227				  enum technisat_usb2_led_state st)
    228{
    229	struct technisat_usb2_state *state = d->priv;
    230	u8 *led = state->buf;
    231	int ret;
    232
    233	led[0] = red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST;
    234
    235	if (disable_led_control && st != TECH_LED_OFF)
    236		return 0;
    237
    238	switch (st) {
    239	case TECH_LED_ON:
    240		led[1] = 0x82;
    241		break;
    242	case TECH_LED_BLINK:
    243		led[1] = 0x82;
    244		if (red) {
    245			led[2] = 0x02;
    246			led[3] = 10;
    247			led[4] = 10;
    248		} else {
    249			led[2] = 0xff;
    250			led[3] = 50;
    251			led[4] = 50;
    252		}
    253		led[5] = 1;
    254		break;
    255
    256	default:
    257	case TECH_LED_OFF:
    258		led[1] = 0x80;
    259		break;
    260	}
    261
    262	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
    263		return -EAGAIN;
    264
    265	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
    266		red ? SET_RED_LED_VENDOR_REQUEST : SET_GREEN_LED_VENDOR_REQUEST,
    267		USB_TYPE_VENDOR | USB_DIR_OUT,
    268		0, 0,
    269		led, 8, 500);
    270
    271	mutex_unlock(&d->i2c_mutex);
    272	return ret;
    273}
    274
    275static int technisat_usb2_set_led_timer(struct dvb_usb_device *d, u8 red, u8 green)
    276{
    277	struct technisat_usb2_state *state = d->priv;
    278	u8 *b = state->buf;
    279	int ret;
    280
    281	b[0] = 0;
    282
    283	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
    284		return -EAGAIN;
    285
    286	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
    287		SET_LED_TIMER_DIVIDER_VENDOR_REQUEST,
    288		USB_TYPE_VENDOR | USB_DIR_OUT,
    289		(red << 8) | green, 0,
    290		b, 1, 500);
    291
    292	mutex_unlock(&d->i2c_mutex);
    293
    294	return ret;
    295}
    296
    297static void technisat_usb2_green_led_control(struct work_struct *work)
    298{
    299	struct technisat_usb2_state *state =
    300		container_of(work, struct technisat_usb2_state, green_led_work.work);
    301	struct dvb_frontend *fe = state->dev->adapter[0].fe_adap[0].fe;
    302
    303	if (state->power_state == 0)
    304		goto schedule;
    305
    306	if (fe != NULL) {
    307		enum fe_status status;
    308
    309		if (fe->ops.read_status(fe, &status) != 0)
    310			goto schedule;
    311
    312		if (status & FE_HAS_LOCK) {
    313			u32 ber;
    314
    315			if (fe->ops.read_ber(fe, &ber) != 0)
    316				goto schedule;
    317
    318			if (ber > 1000)
    319				technisat_usb2_set_led(state->dev, 0, TECH_LED_BLINK);
    320			else
    321				technisat_usb2_set_led(state->dev, 0, TECH_LED_ON);
    322		} else
    323			technisat_usb2_set_led(state->dev, 0, TECH_LED_OFF);
    324	}
    325
    326schedule:
    327	schedule_delayed_work(&state->green_led_work,
    328			msecs_to_jiffies(500));
    329}
    330
    331/* method to find out whether the firmware has to be downloaded or not */
    332static int technisat_usb2_identify_state(struct usb_device *udev,
    333		const struct dvb_usb_device_properties *props,
    334		const struct dvb_usb_device_description **desc, int *cold)
    335{
    336	int ret;
    337	u8 *version;
    338
    339	version = kmalloc(3, GFP_KERNEL);
    340	if (!version)
    341		return -ENOMEM;
    342
    343	/* first select the interface */
    344	if (usb_set_interface(udev, 0, 1) != 0)
    345		err("could not set alternate setting to 0");
    346	else
    347		info("set alternate setting");
    348
    349	*cold = 0; /* by default do not download a firmware - just in case something is wrong */
    350
    351	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
    352		GET_VERSION_INFO_VENDOR_REQUEST,
    353		USB_TYPE_VENDOR | USB_DIR_IN,
    354		0, 0,
    355		version, 3, 500);
    356
    357	if (ret < 0)
    358		*cold = 1;
    359	else {
    360		info("firmware version: %d.%d", version[1], version[2]);
    361		*cold = 0;
    362	}
    363
    364	kfree(version);
    365
    366	return 0;
    367}
    368
    369/* power control */
    370static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
    371{
    372	struct technisat_usb2_state *state = d->priv;
    373
    374	state->power_state = level;
    375
    376	if (disable_led_control)
    377		return 0;
    378
    379	/* green led is turned off in any case - will be turned on when tuning */
    380	technisat_usb2_set_led(d, 0, TECH_LED_OFF);
    381	/* red led is turned on all the time */
    382	technisat_usb2_set_led(d, 1, TECH_LED_ON);
    383	return 0;
    384}
    385
    386/* mac address reading - from the eeprom */
    387#if 0
    388static void technisat_usb2_eeprom_dump(struct dvb_usb_device *d)
    389{
    390	u8 reg;
    391	u8 b[16];
    392	int i, j;
    393
    394	/* full EEPROM dump */
    395	for (j = 0; j < 256 * 4; j += 16) {
    396		reg = j;
    397		if (technisat_usb2_i2c_access(d->udev, 0x50 + j / 256, &reg, 1, b, 16) != 0)
    398			break;
    399
    400		deb_eeprom("EEPROM: %01x%02x: ", j / 256, reg);
    401		for (i = 0; i < 16; i++)
    402			deb_eeprom("%02x ", b[i]);
    403		deb_eeprom("\n");
    404	}
    405}
    406#endif
    407
    408static u8 technisat_usb2_calc_lrc(const u8 *b, u16 length)
    409{
    410	u8 lrc = 0;
    411	while (--length)
    412		lrc ^= *b++;
    413	return lrc;
    414}
    415
    416static int technisat_usb2_eeprom_lrc_read(struct dvb_usb_device *d,
    417	u16 offset, u8 *b, u16 length, u8 tries)
    418{
    419	u8 bo = offset & 0xff;
    420	struct i2c_msg msg[] = {
    421		{
    422			.addr = 0x50 | ((offset >> 8) & 0x3),
    423			.buf = &bo,
    424			.len = 1
    425		}, {
    426			.addr = 0x50 | ((offset >> 8) & 0x3),
    427			.flags	= I2C_M_RD,
    428			.buf = b,
    429			.len = length
    430		}
    431	};
    432
    433	while (tries--) {
    434		int status;
    435
    436		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
    437			break;
    438
    439		status =
    440			technisat_usb2_calc_lrc(b, length - 1) == b[length - 1];
    441
    442		if (status)
    443			return 0;
    444	}
    445
    446	return -EREMOTEIO;
    447}
    448
    449#define EEPROM_MAC_START 0x3f8
    450#define EEPROM_MAC_TOTAL 8
    451static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
    452		u8 mac[])
    453{
    454	u8 buf[EEPROM_MAC_TOTAL];
    455
    456	if (technisat_usb2_eeprom_lrc_read(d, EEPROM_MAC_START,
    457				buf, EEPROM_MAC_TOTAL, 4) != 0)
    458		return -ENODEV;
    459
    460	memcpy(mac, buf, 6);
    461	return 0;
    462}
    463
    464static struct stv090x_config technisat_usb2_stv090x_config;
    465
    466/* frontend attach */
    467static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
    468				      enum fe_sec_voltage voltage)
    469{
    470	int i;
    471	u8 gpio[3] = { 0 }; /* 0 = 2, 1 = 3, 2 = 4 */
    472
    473	gpio[2] = 1; /* high - voltage ? */
    474
    475	switch (voltage) {
    476	case SEC_VOLTAGE_13:
    477		gpio[0] = 1;
    478		break;
    479	case SEC_VOLTAGE_18:
    480		gpio[0] = 1;
    481		gpio[1] = 1;
    482		break;
    483	default:
    484	case SEC_VOLTAGE_OFF:
    485		break;
    486	}
    487
    488	for (i = 0; i < 3; i++)
    489		if (technisat_usb2_stv090x_config.set_gpio(fe, i+2, 0,
    490							   gpio[i], 0) != 0)
    491			return -EREMOTEIO;
    492	return 0;
    493}
    494
    495static struct stv090x_config technisat_usb2_stv090x_config = {
    496	.device         = STV0903,
    497	.demod_mode     = STV090x_SINGLE,
    498	.clk_mode       = STV090x_CLK_EXT,
    499
    500	.xtal           = 8000000,
    501	.address        = 0x68,
    502
    503	.ts1_mode       = STV090x_TSMODE_DVBCI,
    504	.ts1_clk        = 13400000,
    505	.ts1_tei        = 1,
    506
    507	.repeater_level = STV090x_RPTLEVEL_64,
    508
    509	.tuner_bbgain   = 6,
    510};
    511
    512static struct stv6110x_config technisat_usb2_stv6110x_config = {
    513	.addr           = 0x60,
    514	.refclk         = 16000000,
    515	.clk_div        = 2,
    516};
    517
    518static int technisat_usb2_frontend_attach(struct dvb_usb_adapter *a)
    519{
    520	struct usb_device *udev = a->dev->udev;
    521	int ret;
    522
    523	a->fe_adap[0].fe = dvb_attach(stv090x_attach, &technisat_usb2_stv090x_config,
    524			&a->dev->i2c_adap, STV090x_DEMODULATOR_0);
    525
    526	if (a->fe_adap[0].fe) {
    527		const struct stv6110x_devctl *ctl;
    528
    529		ctl = dvb_attach(stv6110x_attach,
    530				a->fe_adap[0].fe,
    531				&technisat_usb2_stv6110x_config,
    532				&a->dev->i2c_adap);
    533
    534		if (ctl) {
    535			technisat_usb2_stv090x_config.tuner_init          = ctl->tuner_init;
    536			technisat_usb2_stv090x_config.tuner_sleep         = ctl->tuner_sleep;
    537			technisat_usb2_stv090x_config.tuner_set_mode      = ctl->tuner_set_mode;
    538			technisat_usb2_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;
    539			technisat_usb2_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;
    540			technisat_usb2_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;
    541			technisat_usb2_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;
    542			technisat_usb2_stv090x_config.tuner_set_bbgain    = ctl->tuner_set_bbgain;
    543			technisat_usb2_stv090x_config.tuner_get_bbgain    = ctl->tuner_get_bbgain;
    544			technisat_usb2_stv090x_config.tuner_set_refclk    = ctl->tuner_set_refclk;
    545			technisat_usb2_stv090x_config.tuner_get_status    = ctl->tuner_get_status;
    546
    547			/* call the init function once to initialize
    548			   tuner's clock output divider and demod's
    549			   master clock */
    550			if (a->fe_adap[0].fe->ops.init)
    551				a->fe_adap[0].fe->ops.init(a->fe_adap[0].fe);
    552
    553			if (mutex_lock_interruptible(&a->dev->i2c_mutex) < 0)
    554				return -EAGAIN;
    555
    556			ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
    557					SET_IFCLK_TO_EXTERNAL_TSCLK_VENDOR_REQUEST,
    558					USB_TYPE_VENDOR | USB_DIR_OUT,
    559					0, 0,
    560					NULL, 0, 500);
    561			mutex_unlock(&a->dev->i2c_mutex);
    562
    563			if (ret != 0)
    564				err("could not set IF_CLK to external");
    565
    566			a->fe_adap[0].fe->ops.set_voltage = technisat_usb2_set_voltage;
    567
    568			/* if everything was successful assign a nice name to the frontend */
    569			strscpy(a->fe_adap[0].fe->ops.info.name,
    570				a->dev->desc->name,
    571				sizeof(a->fe_adap[0].fe->ops.info.name));
    572		} else {
    573			dvb_frontend_detach(a->fe_adap[0].fe);
    574			a->fe_adap[0].fe = NULL;
    575		}
    576	}
    577
    578	technisat_usb2_set_led_timer(a->dev, 1, 1);
    579
    580	return a->fe_adap[0].fe == NULL ? -ENODEV : 0;
    581}
    582
    583/* Remote control */
    584
    585/* the device is giving providing raw IR-signals to the host mapping
    586 * it only to one remote control is just the default implementation
    587 */
    588#define NOMINAL_IR_BIT_TRANSITION_TIME_US 889
    589#define NOMINAL_IR_BIT_TIME_US (2 * NOMINAL_IR_BIT_TRANSITION_TIME_US)
    590
    591#define FIRMWARE_CLOCK_TICK 83333
    592#define FIRMWARE_CLOCK_DIVISOR 256
    593
    594#define IR_PERCENT_TOLERANCE 15
    595
    596#define NOMINAL_IR_BIT_TRANSITION_TICKS ((NOMINAL_IR_BIT_TRANSITION_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
    597#define NOMINAL_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICKS / FIRMWARE_CLOCK_DIVISOR)
    598
    599#define NOMINAL_IR_BIT_TIME_TICKS ((NOMINAL_IR_BIT_TIME_US * 1000 * 1000) / FIRMWARE_CLOCK_TICK)
    600#define NOMINAL_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICKS / FIRMWARE_CLOCK_DIVISOR)
    601
    602#define MINIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT - ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
    603#define MAXIMUM_IR_BIT_TRANSITION_TICK_COUNT (NOMINAL_IR_BIT_TRANSITION_TICK_COUNT + ((NOMINAL_IR_BIT_TRANSITION_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
    604
    605#define MINIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT - ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
    606#define MAXIMUM_IR_BIT_TIME_TICK_COUNT (NOMINAL_IR_BIT_TIME_TICK_COUNT + ((NOMINAL_IR_BIT_TIME_TICK_COUNT * IR_PERCENT_TOLERANCE) / 100))
    607
    608static int technisat_usb2_get_ir(struct dvb_usb_device *d)
    609{
    610	struct technisat_usb2_state *state = d->priv;
    611	struct ir_raw_event ev;
    612	u8 *buf = state->buf;
    613	int i, ret;
    614
    615	buf[0] = GET_IR_DATA_VENDOR_REQUEST;
    616	buf[1] = 0x08;
    617	buf[2] = 0x8f;
    618	buf[3] = MINIMUM_IR_BIT_TRANSITION_TICK_COUNT;
    619	buf[4] = MAXIMUM_IR_BIT_TIME_TICK_COUNT;
    620
    621	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
    622		return -EAGAIN;
    623	ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
    624			GET_IR_DATA_VENDOR_REQUEST,
    625			USB_TYPE_VENDOR | USB_DIR_OUT,
    626			0, 0,
    627			buf, 5, 500);
    628	if (ret < 0)
    629		goto unlock;
    630
    631	buf[1] = 0;
    632	buf[2] = 0;
    633	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
    634			GET_IR_DATA_VENDOR_REQUEST,
    635			USB_TYPE_VENDOR | USB_DIR_IN,
    636			0x8080, 0,
    637			buf, 62, 500);
    638
    639unlock:
    640	mutex_unlock(&d->i2c_mutex);
    641
    642	if (ret < 0)
    643		return ret;
    644
    645	if (ret == 1)
    646		return 0; /* no key pressed */
    647
    648	/* decoding */
    649
    650#if 0
    651	deb_rc("RC: %d ", ret);
    652	debug_dump(buf + 1, ret, deb_rc);
    653#endif
    654
    655	ev.pulse = 0;
    656	for (i = 1; i < ARRAY_SIZE(state->buf); i++) {
    657		if (buf[i] == 0xff) {
    658			ev.pulse = 0;
    659			ev.duration = 889 * 2;
    660			ir_raw_event_store(d->rc_dev, &ev);
    661			break;
    662		}
    663
    664		ev.pulse = !ev.pulse;
    665		ev.duration = (buf[i] * FIRMWARE_CLOCK_DIVISOR *
    666			       FIRMWARE_CLOCK_TICK) / (1000 * 1000);
    667		ir_raw_event_store(d->rc_dev, &ev);
    668	}
    669
    670	ir_raw_event_handle(d->rc_dev);
    671
    672	return 1;
    673}
    674
    675static int technisat_usb2_rc_query(struct dvb_usb_device *d)
    676{
    677	int ret = technisat_usb2_get_ir(d);
    678
    679	if (ret < 0)
    680		return ret;
    681
    682	if (ret == 0)
    683		return 0;
    684
    685	if (!disable_led_control)
    686		technisat_usb2_set_led(d, 1, TECH_LED_BLINK);
    687
    688	return 0;
    689}
    690
    691/* DVB-USB and USB stuff follows */
    692enum {
    693	TECHNISAT_USB2_DVB_S2,
    694};
    695
    696static struct usb_device_id technisat_usb2_id_table[] = {
    697	DVB_USB_DEV(TECHNISAT, TECHNISAT_USB2_DVB_S2),
    698	{ }
    699};
    700
    701MODULE_DEVICE_TABLE(usb, technisat_usb2_id_table);
    702
    703/* device description */
    704static struct dvb_usb_device_properties technisat_usb2_devices = {
    705	.caps              = DVB_USB_IS_AN_I2C_ADAPTER,
    706
    707	.usb_ctrl          = CYPRESS_FX2,
    708
    709	.identify_state    = technisat_usb2_identify_state,
    710	.firmware          = "dvb-usb-SkyStar_USB_HD_FW_v17_63.HEX.fw",
    711
    712	.size_of_priv      = sizeof(struct technisat_usb2_state),
    713
    714	.i2c_algo          = &technisat_usb2_i2c_algo,
    715
    716	.power_ctrl        = technisat_usb2_power_ctrl,
    717	.read_mac_address  = technisat_usb2_read_mac_address,
    718
    719	.num_adapters = 1,
    720	.adapter = {
    721		{
    722		.num_frontends = 1,
    723		.fe = {{
    724			.frontend_attach  = technisat_usb2_frontend_attach,
    725
    726			.stream = {
    727				.type = USB_ISOC,
    728				.count = 4,
    729				.endpoint = 0x2,
    730				.u = {
    731					.isoc = {
    732						.framesperurb = 32,
    733						.framesize = 2048,
    734						.interval = 1,
    735					}
    736				}
    737			},
    738		}},
    739			.size_of_priv = 0,
    740		},
    741	},
    742
    743	.num_device_descs = 1,
    744	.devices = {
    745		{   "Technisat SkyStar USB HD (DVB-S/S2)",
    746			{ &technisat_usb2_id_table[TECHNISAT_USB2_DVB_S2], NULL },
    747			{ NULL },
    748		},
    749	},
    750
    751	.rc.core = {
    752		.rc_interval = 100,
    753		.rc_codes    = RC_MAP_TECHNISAT_USB2,
    754		.module_name = "technisat-usb2",
    755		.rc_query    = technisat_usb2_rc_query,
    756		.allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER,
    757		.driver_type    = RC_DRIVER_IR_RAW,
    758	}
    759};
    760
    761static int technisat_usb2_probe(struct usb_interface *intf,
    762		const struct usb_device_id *id)
    763{
    764	struct dvb_usb_device *dev;
    765
    766	if (dvb_usb_device_init(intf, &technisat_usb2_devices, THIS_MODULE,
    767				&dev, adapter_nr) != 0)
    768		return -ENODEV;
    769
    770	if (dev) {
    771		struct technisat_usb2_state *state = dev->priv;
    772		state->dev = dev;
    773
    774		if (!disable_led_control) {
    775			INIT_DELAYED_WORK(&state->green_led_work,
    776					technisat_usb2_green_led_control);
    777			schedule_delayed_work(&state->green_led_work,
    778					msecs_to_jiffies(500));
    779		}
    780	}
    781
    782	return 0;
    783}
    784
    785static void technisat_usb2_disconnect(struct usb_interface *intf)
    786{
    787	struct dvb_usb_device *dev = usb_get_intfdata(intf);
    788
    789	/* work and stuff was only created when the device is is hot-state */
    790	if (dev != NULL) {
    791		struct technisat_usb2_state *state = dev->priv;
    792		if (state != NULL)
    793			cancel_delayed_work_sync(&state->green_led_work);
    794	}
    795
    796	dvb_usb_device_exit(intf);
    797}
    798
    799static struct usb_driver technisat_usb2_driver = {
    800	.name       = "dvb_usb_technisat_usb2",
    801	.probe      = technisat_usb2_probe,
    802	.disconnect = technisat_usb2_disconnect,
    803	.id_table   = technisat_usb2_id_table,
    804};
    805
    806module_usb_driver(technisat_usb2_driver);
    807
    808MODULE_AUTHOR("Patrick Boettcher <pboettcher@kernellabs.com>");
    809MODULE_DESCRIPTION("Driver for Technisat DVB-S/S2 USB 2.0 device");
    810MODULE_VERSION("1.0");
    811MODULE_LICENSE("GPL");