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

cinergyT2-fe.c (7024B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
      4 *
      5 * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
      6 *
      7 * Based on the dvb-usb-framework code and the
      8 * original Terratec Cinergy T2 driver by:
      9 *
     10 * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
     11 *                  Holger Waechtler <holger@qanu.de>
     12 *
     13 *  Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
     14 */
     15
     16#include "cinergyT2.h"
     17
     18
     19/*
     20 *  convert linux-dvb frontend parameter set into TPS.
     21 *  See ETSI ETS-300744, section 4.6.2, table 9 for details.
     22 *
     23 *  This function is probably reusable and may better get placed in a support
     24 *  library.
     25 *
     26 *  We replace erroneous fields by default TPS fields (the ones with value 0).
     27 */
     28
     29static uint16_t compute_tps(struct dtv_frontend_properties *op)
     30{
     31	uint16_t tps = 0;
     32
     33	switch (op->code_rate_HP) {
     34	case FEC_2_3:
     35		tps |= (1 << 7);
     36		break;
     37	case FEC_3_4:
     38		tps |= (2 << 7);
     39		break;
     40	case FEC_5_6:
     41		tps |= (3 << 7);
     42		break;
     43	case FEC_7_8:
     44		tps |= (4 << 7);
     45		break;
     46	case FEC_1_2:
     47	case FEC_AUTO:
     48	default:
     49		/* tps |= (0 << 7) */;
     50	}
     51
     52	switch (op->code_rate_LP) {
     53	case FEC_2_3:
     54		tps |= (1 << 4);
     55		break;
     56	case FEC_3_4:
     57		tps |= (2 << 4);
     58		break;
     59	case FEC_5_6:
     60		tps |= (3 << 4);
     61		break;
     62	case FEC_7_8:
     63		tps |= (4 << 4);
     64		break;
     65	case FEC_1_2:
     66	case FEC_AUTO:
     67	default:
     68		/* tps |= (0 << 4) */;
     69	}
     70
     71	switch (op->modulation) {
     72	case QAM_16:
     73		tps |= (1 << 13);
     74		break;
     75	case QAM_64:
     76		tps |= (2 << 13);
     77		break;
     78	case QPSK:
     79	default:
     80		/* tps |= (0 << 13) */;
     81	}
     82
     83	switch (op->transmission_mode) {
     84	case TRANSMISSION_MODE_8K:
     85		tps |= (1 << 0);
     86		break;
     87	case TRANSMISSION_MODE_2K:
     88	default:
     89		/* tps |= (0 << 0) */;
     90	}
     91
     92	switch (op->guard_interval) {
     93	case GUARD_INTERVAL_1_16:
     94		tps |= (1 << 2);
     95		break;
     96	case GUARD_INTERVAL_1_8:
     97		tps |= (2 << 2);
     98		break;
     99	case GUARD_INTERVAL_1_4:
    100		tps |= (3 << 2);
    101		break;
    102	case GUARD_INTERVAL_1_32:
    103	default:
    104		/* tps |= (0 << 2) */;
    105	}
    106
    107	switch (op->hierarchy) {
    108	case HIERARCHY_1:
    109		tps |= (1 << 10);
    110		break;
    111	case HIERARCHY_2:
    112		tps |= (2 << 10);
    113		break;
    114	case HIERARCHY_4:
    115		tps |= (3 << 10);
    116		break;
    117	case HIERARCHY_NONE:
    118	default:
    119		/* tps |= (0 << 10) */;
    120	}
    121
    122	return tps;
    123}
    124
    125struct cinergyt2_fe_state {
    126	struct dvb_frontend fe;
    127	struct dvb_usb_device *d;
    128
    129	unsigned char data[64];
    130	struct mutex data_mutex;
    131
    132	struct dvbt_get_status_msg status;
    133};
    134
    135static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
    136				    enum fe_status *status)
    137{
    138	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    139	int ret;
    140
    141	mutex_lock(&state->data_mutex);
    142	state->data[0] = CINERGYT2_EP1_GET_TUNER_STATUS;
    143
    144	ret = dvb_usb_generic_rw(state->d, state->data, 1,
    145				 state->data, sizeof(state->status), 0);
    146	if (!ret)
    147		memcpy(&state->status, state->data, sizeof(state->status));
    148	mutex_unlock(&state->data_mutex);
    149
    150	if (ret < 0)
    151		return ret;
    152
    153	*status = 0;
    154
    155	if (0xffff - le16_to_cpu(state->status.gain) > 30)
    156		*status |= FE_HAS_SIGNAL;
    157	if (state->status.lock_bits & (1 << 6))
    158		*status |= FE_HAS_LOCK;
    159	if (state->status.lock_bits & (1 << 5))
    160		*status |= FE_HAS_SYNC;
    161	if (state->status.lock_bits & (1 << 4))
    162		*status |= FE_HAS_CARRIER;
    163	if (state->status.lock_bits & (1 << 1))
    164		*status |= FE_HAS_VITERBI;
    165
    166	if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
    167			(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
    168		*status &= ~FE_HAS_LOCK;
    169
    170	return 0;
    171}
    172
    173static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
    174{
    175	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    176
    177	*ber = le32_to_cpu(state->status.viterbi_error_rate);
    178	return 0;
    179}
    180
    181static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
    182{
    183	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    184
    185	*unc = le32_to_cpu(state->status.uncorrected_block_count);
    186	return 0;
    187}
    188
    189static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
    190						u16 *strength)
    191{
    192	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    193
    194	*strength = (0xffff - le16_to_cpu(state->status.gain));
    195	return 0;
    196}
    197
    198static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
    199{
    200	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    201
    202	*snr = (state->status.snr << 8) | state->status.snr;
    203	return 0;
    204}
    205
    206static int cinergyt2_fe_init(struct dvb_frontend *fe)
    207{
    208	return 0;
    209}
    210
    211static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
    212{
    213	deb_info("cinergyt2_fe_sleep() Called\n");
    214	return 0;
    215}
    216
    217static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
    218				struct dvb_frontend_tune_settings *tune)
    219{
    220	tune->min_delay_ms = 800;
    221	return 0;
    222}
    223
    224static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
    225{
    226	struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
    227	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    228	struct dvbt_set_parameters_msg *param;
    229	int err;
    230
    231	mutex_lock(&state->data_mutex);
    232
    233	param = (void *)state->data;
    234	param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;
    235	param->tps = cpu_to_le16(compute_tps(fep));
    236	param->freq = cpu_to_le32(fep->frequency / 1000);
    237	param->flags = 0;
    238
    239	switch (fep->bandwidth_hz) {
    240	default:
    241	case 8000000:
    242		param->bandwidth = 8;
    243		break;
    244	case 7000000:
    245		param->bandwidth = 7;
    246		break;
    247	case 6000000:
    248		param->bandwidth = 6;
    249		break;
    250	}
    251
    252	err = dvb_usb_generic_rw(state->d, state->data, sizeof(*param),
    253				 state->data, 2, 0);
    254	if (err < 0)
    255		err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
    256
    257	mutex_unlock(&state->data_mutex);
    258	return (err < 0) ? err : 0;
    259}
    260
    261static void cinergyt2_fe_release(struct dvb_frontend *fe)
    262{
    263	struct cinergyt2_fe_state *state = fe->demodulator_priv;
    264	kfree(state);
    265}
    266
    267static const struct dvb_frontend_ops cinergyt2_fe_ops;
    268
    269struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)
    270{
    271	struct cinergyt2_fe_state *s = kzalloc(sizeof(
    272					struct cinergyt2_fe_state), GFP_KERNEL);
    273	if (s == NULL)
    274		return NULL;
    275
    276	s->d = d;
    277	memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
    278	s->fe.demodulator_priv = s;
    279	mutex_init(&s->data_mutex);
    280	return &s->fe;
    281}
    282
    283
    284static const struct dvb_frontend_ops cinergyt2_fe_ops = {
    285	.delsys = { SYS_DVBT },
    286	.info = {
    287		.name			= DRIVER_NAME,
    288		.frequency_min_hz	= 174 * MHz,
    289		.frequency_max_hz	= 862 * MHz,
    290		.frequency_stepsize_hz	= 166667,
    291		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2
    292			| FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
    293			| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8
    294			| FE_CAN_FEC_AUTO | FE_CAN_QPSK
    295			| FE_CAN_QAM_16 | FE_CAN_QAM_64
    296			| FE_CAN_QAM_AUTO
    297			| FE_CAN_TRANSMISSION_MODE_AUTO
    298			| FE_CAN_GUARD_INTERVAL_AUTO
    299			| FE_CAN_HIERARCHY_AUTO
    300			| FE_CAN_RECOVER
    301			| FE_CAN_MUTE_TS
    302	},
    303
    304	.release		= cinergyt2_fe_release,
    305
    306	.init			= cinergyt2_fe_init,
    307	.sleep			= cinergyt2_fe_sleep,
    308
    309	.set_frontend		= cinergyt2_fe_set_frontend,
    310	.get_tune_settings	= cinergyt2_fe_get_tune_settings,
    311
    312	.read_status		= cinergyt2_fe_read_status,
    313	.read_ber		= cinergyt2_fe_read_ber,
    314	.read_signal_strength	= cinergyt2_fe_read_signal_strength,
    315	.read_snr		= cinergyt2_fe_read_snr,
    316	.read_ucblocks		= cinergyt2_fe_read_unc_blocks,
    317};