Path: blob/master/drivers/media/dvb/dvb-usb/cinergyT2-fe.c
15111 views
/*1* TerraTec Cinergy T2/qanu USB2 DVB-T adapter.2*3* Copyright (C) 2007 Tomi Orava ([email protected])4*5* Based on the dvb-usb-framework code and the6* original Terratec Cinergy T2 driver by:7*8* Copyright (C) 2004 Daniel Mack <[email protected]> and9* Holger Waechtler <[email protected]>10*11* Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf12*13* This program is free software; you can redistribute it and/or modify14* it under the terms of the GNU General Public License as published by15* the Free Software Foundation; either version 2 of the License, or16* (at your option) any later version.17*18* This program is distributed in the hope that it will be useful,19* but WITHOUT ANY WARRANTY; without even the implied warranty of20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the21* GNU General Public License for more details.22*23* You should have received a copy of the GNU General Public License24* along with this program; if not, write to the Free Software25* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.26*27*/2829#include "cinergyT2.h"303132/**33* convert linux-dvb frontend parameter set into TPS.34* See ETSI ETS-300744, section 4.6.2, table 9 for details.35*36* This function is probably reusable and may better get placed in a support37* library.38*39* We replace errornous fields by default TPS fields (the ones with value 0).40*/4142static uint16_t compute_tps(struct dvb_frontend_parameters *p)43{44struct dvb_ofdm_parameters *op = &p->u.ofdm;45uint16_t tps = 0;4647switch (op->code_rate_HP) {48case FEC_2_3:49tps |= (1 << 7);50break;51case FEC_3_4:52tps |= (2 << 7);53break;54case FEC_5_6:55tps |= (3 << 7);56break;57case FEC_7_8:58tps |= (4 << 7);59break;60case FEC_1_2:61case FEC_AUTO:62default:63/* tps |= (0 << 7) */;64}6566switch (op->code_rate_LP) {67case FEC_2_3:68tps |= (1 << 4);69break;70case FEC_3_4:71tps |= (2 << 4);72break;73case FEC_5_6:74tps |= (3 << 4);75break;76case FEC_7_8:77tps |= (4 << 4);78break;79case FEC_1_2:80case FEC_AUTO:81default:82/* tps |= (0 << 4) */;83}8485switch (op->constellation) {86case QAM_16:87tps |= (1 << 13);88break;89case QAM_64:90tps |= (2 << 13);91break;92case QPSK:93default:94/* tps |= (0 << 13) */;95}9697switch (op->transmission_mode) {98case TRANSMISSION_MODE_8K:99tps |= (1 << 0);100break;101case TRANSMISSION_MODE_2K:102default:103/* tps |= (0 << 0) */;104}105106switch (op->guard_interval) {107case GUARD_INTERVAL_1_16:108tps |= (1 << 2);109break;110case GUARD_INTERVAL_1_8:111tps |= (2 << 2);112break;113case GUARD_INTERVAL_1_4:114tps |= (3 << 2);115break;116case GUARD_INTERVAL_1_32:117default:118/* tps |= (0 << 2) */;119}120121switch (op->hierarchy_information) {122case HIERARCHY_1:123tps |= (1 << 10);124break;125case HIERARCHY_2:126tps |= (2 << 10);127break;128case HIERARCHY_4:129tps |= (3 << 10);130break;131case HIERARCHY_NONE:132default:133/* tps |= (0 << 10) */;134}135136return tps;137}138139struct cinergyt2_fe_state {140struct dvb_frontend fe;141struct dvb_usb_device *d;142};143144static int cinergyt2_fe_read_status(struct dvb_frontend *fe,145fe_status_t *status)146{147struct cinergyt2_fe_state *state = fe->demodulator_priv;148struct dvbt_get_status_msg result;149u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };150int ret;151152ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,153sizeof(result), 0);154if (ret < 0)155return ret;156157*status = 0;158159if (0xffff - le16_to_cpu(result.gain) > 30)160*status |= FE_HAS_SIGNAL;161if (result.lock_bits & (1 << 6))162*status |= FE_HAS_LOCK;163if (result.lock_bits & (1 << 5))164*status |= FE_HAS_SYNC;165if (result.lock_bits & (1 << 4))166*status |= FE_HAS_CARRIER;167if (result.lock_bits & (1 << 1))168*status |= FE_HAS_VITERBI;169170if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=171(FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))172*status &= ~FE_HAS_LOCK;173174return 0;175}176177static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)178{179struct cinergyt2_fe_state *state = fe->demodulator_priv;180struct dvbt_get_status_msg status;181char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };182int ret;183184ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,185sizeof(status), 0);186if (ret < 0)187return ret;188189*ber = le32_to_cpu(status.viterbi_error_rate);190return 0;191}192193static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)194{195struct cinergyt2_fe_state *state = fe->demodulator_priv;196struct dvbt_get_status_msg status;197u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };198int ret;199200ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,201sizeof(status), 0);202if (ret < 0) {203err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",204ret);205return ret;206}207*unc = le32_to_cpu(status.uncorrected_block_count);208return 0;209}210211static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,212u16 *strength)213{214struct cinergyt2_fe_state *state = fe->demodulator_priv;215struct dvbt_get_status_msg status;216char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };217int ret;218219ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,220sizeof(status), 0);221if (ret < 0) {222err("cinergyt2_fe_read_signal_strength() Failed!"223" (Error=%d)\n", ret);224return ret;225}226*strength = (0xffff - le16_to_cpu(status.gain));227return 0;228}229230static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)231{232struct cinergyt2_fe_state *state = fe->demodulator_priv;233struct dvbt_get_status_msg status;234char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };235int ret;236237ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,238sizeof(status), 0);239if (ret < 0) {240err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);241return ret;242}243*snr = (status.snr << 8) | status.snr;244return 0;245}246247static int cinergyt2_fe_init(struct dvb_frontend *fe)248{249return 0;250}251252static int cinergyt2_fe_sleep(struct dvb_frontend *fe)253{254deb_info("cinergyt2_fe_sleep() Called\n");255return 0;256}257258static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,259struct dvb_frontend_tune_settings *tune)260{261tune->min_delay_ms = 800;262return 0;263}264265static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe,266struct dvb_frontend_parameters *fep)267{268struct cinergyt2_fe_state *state = fe->demodulator_priv;269struct dvbt_set_parameters_msg param;270char result[2];271int err;272273param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS;274param.tps = cpu_to_le16(compute_tps(fep));275param.freq = cpu_to_le32(fep->frequency / 1000);276param.bandwidth = 8 - fep->u.ofdm.bandwidth - BANDWIDTH_8_MHZ;277param.flags = 0;278279err = dvb_usb_generic_rw(state->d,280(char *)¶m, sizeof(param),281result, sizeof(result), 0);282if (err < 0)283err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);284285return (err < 0) ? err : 0;286}287288static int cinergyt2_fe_get_frontend(struct dvb_frontend *fe,289struct dvb_frontend_parameters *fep)290{291return 0;292}293294static void cinergyt2_fe_release(struct dvb_frontend *fe)295{296struct cinergyt2_fe_state *state = fe->demodulator_priv;297if (state != NULL)298kfree(state);299}300301static struct dvb_frontend_ops cinergyt2_fe_ops;302303struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d)304{305struct cinergyt2_fe_state *s = kzalloc(sizeof(306struct cinergyt2_fe_state), GFP_KERNEL);307if (s == NULL)308return NULL;309310s->d = d;311memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));312s->fe.demodulator_priv = s;313return &s->fe;314}315316317static struct dvb_frontend_ops cinergyt2_fe_ops = {318.info = {319.name = DRIVER_NAME,320.type = FE_OFDM,321.frequency_min = 174000000,322.frequency_max = 862000000,323.frequency_stepsize = 166667,324.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2325| FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4326| FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8327| FE_CAN_FEC_AUTO | FE_CAN_QPSK328| FE_CAN_QAM_16 | FE_CAN_QAM_64329| FE_CAN_QAM_AUTO330| FE_CAN_TRANSMISSION_MODE_AUTO331| FE_CAN_GUARD_INTERVAL_AUTO332| FE_CAN_HIERARCHY_AUTO333| FE_CAN_RECOVER334| FE_CAN_MUTE_TS335},336337.release = cinergyt2_fe_release,338339.init = cinergyt2_fe_init,340.sleep = cinergyt2_fe_sleep,341342.set_frontend = cinergyt2_fe_set_frontend,343.get_frontend = cinergyt2_fe_get_frontend,344.get_tune_settings = cinergyt2_fe_get_tune_settings,345346.read_status = cinergyt2_fe_read_status,347.read_ber = cinergyt2_fe_read_ber,348.read_signal_strength = cinergyt2_fe_read_signal_strength,349.read_snr = cinergyt2_fe_read_snr,350.read_ucblocks = cinergyt2_fe_read_unc_blocks,351};352353354