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