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