linux/drivers/media/usb/dvb-usb/dtt200u-fe.c
<<
>>
Prefs
   1/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
   2 * Typhoon/ Yuan DVB-T USB2.0 receiver.
   3 *
   4 * Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@posteo.de>
   5 *
   6 *      This program is free software; you can redistribute it and/or modify it
   7 *      under the terms of the GNU General Public License as published by the Free
   8 *      Software Foundation, version 2.
   9 *
  10 * see Documentation/dvb/README.dvb-usb for more information
  11 */
  12#include "dtt200u.h"
  13
  14struct dtt200u_fe_state {
  15        struct dvb_usb_device *d;
  16
  17        enum fe_status stat;
  18
  19        struct dtv_frontend_properties fep;
  20        struct dvb_frontend frontend;
  21
  22        unsigned char data[80];
  23        struct mutex data_mutex;
  24};
  25
  26static int dtt200u_fe_read_status(struct dvb_frontend *fe,
  27                                  enum fe_status *stat)
  28{
  29        struct dtt200u_fe_state *state = fe->demodulator_priv;
  30        int ret;
  31
  32        mutex_lock(&state->data_mutex);
  33        state->data[0] = GET_TUNE_STATUS;
  34
  35        ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 3, 0);
  36        if (ret < 0) {
  37                *stat = 0;
  38                mutex_unlock(&state->data_mutex);
  39                return ret;
  40        }
  41
  42        switch (state->data[0]) {
  43                case 0x01:
  44                        *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
  45                                FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
  46                        break;
  47                case 0x00: /* pending */
  48                        *stat = FE_TIMEDOUT; /* during set_frontend */
  49                        break;
  50                default:
  51                case 0x02: /* failed */
  52                        *stat = 0;
  53                        break;
  54        }
  55        mutex_unlock(&state->data_mutex);
  56        return 0;
  57}
  58
  59static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
  60{
  61        struct dtt200u_fe_state *state = fe->demodulator_priv;
  62        int ret;
  63
  64        mutex_lock(&state->data_mutex);
  65        state->data[0] = GET_VIT_ERR_CNT;
  66
  67        ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 3, 0);
  68        if (ret >= 0)
  69                *ber = (state->data[0] << 16) | (state->data[1] << 8) | state->data[2];
  70
  71        mutex_unlock(&state->data_mutex);
  72        return ret;
  73}
  74
  75static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
  76{
  77        struct dtt200u_fe_state *state = fe->demodulator_priv;
  78        int ret;
  79
  80        mutex_lock(&state->data_mutex);
  81        state->data[0] = GET_RS_UNCOR_BLK_CNT;
  82
  83        ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 2, 0);
  84        if (ret >= 0)
  85                *unc = (state->data[0] << 8) | state->data[1];
  86
  87        mutex_unlock(&state->data_mutex);
  88        return ret;
  89}
  90
  91static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
  92{
  93        struct dtt200u_fe_state *state = fe->demodulator_priv;
  94        int ret;
  95
  96        mutex_lock(&state->data_mutex);
  97        state->data[0] = GET_AGC;
  98
  99        ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 1, 0);
 100        if (ret >= 0)
 101                *strength = (state->data[0] << 8) | state->data[0];
 102
 103        mutex_unlock(&state->data_mutex);
 104        return ret;
 105}
 106
 107static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
 108{
 109        struct dtt200u_fe_state *state = fe->demodulator_priv;
 110        int ret;
 111
 112        mutex_lock(&state->data_mutex);
 113        state->data[0] = GET_SNR;
 114
 115        ret = dvb_usb_generic_rw(state->d, state->data, 1, state->data, 1, 0);
 116        if (ret >= 0)
 117                *snr = ~((state->data[0] << 8) | state->data[0]);
 118
 119        mutex_unlock(&state->data_mutex);
 120        return ret;
 121}
 122
 123static int dtt200u_fe_init(struct dvb_frontend* fe)
 124{
 125        struct dtt200u_fe_state *state = fe->demodulator_priv;
 126        int ret;
 127
 128        mutex_lock(&state->data_mutex);
 129        state->data[0] = SET_INIT;
 130
 131        ret = dvb_usb_generic_write(state->d, state->data, 1);
 132        mutex_unlock(&state->data_mutex);
 133
 134        return ret;
 135}
 136
 137static int dtt200u_fe_sleep(struct dvb_frontend* fe)
 138{
 139        return dtt200u_fe_init(fe);
 140}
 141
 142static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
 143{
 144        tune->min_delay_ms = 1500;
 145        tune->step_size = 0;
 146        tune->max_drift = 0;
 147        return 0;
 148}
 149
 150static int dtt200u_fe_set_frontend(struct dvb_frontend *fe)
 151{
 152        struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
 153        struct dtt200u_fe_state *state = fe->demodulator_priv;
 154        int ret;
 155        u16 freq = fep->frequency / 250000;
 156
 157        mutex_lock(&state->data_mutex);
 158        state->data[0] = SET_BANDWIDTH;
 159        switch (fep->bandwidth_hz) {
 160        case 8000000:
 161                state->data[1] = 8;
 162                break;
 163        case 7000000:
 164                state->data[1] = 7;
 165                break;
 166        case 6000000:
 167                state->data[1] = 6;
 168                break;
 169        default:
 170                ret = -EINVAL;
 171                goto ret;
 172        }
 173
 174        ret = dvb_usb_generic_write(state->d, state->data, 2);
 175        if (ret < 0)
 176                goto ret;
 177
 178        state->data[0] = SET_RF_FREQ;
 179        state->data[1] = freq & 0xff;
 180        state->data[2] = (freq >> 8) & 0xff;
 181        ret = dvb_usb_generic_write(state->d, state->data, 3);
 182        if (ret < 0)
 183                goto ret;
 184
 185ret:
 186        mutex_unlock(&state->data_mutex);
 187        return ret;
 188}
 189
 190static int dtt200u_fe_get_frontend(struct dvb_frontend* fe,
 191                                   struct dtv_frontend_properties *fep)
 192{
 193        struct dtt200u_fe_state *state = fe->demodulator_priv;
 194
 195        memcpy(fep, &state->fep, sizeof(struct dtv_frontend_properties));
 196        return 0;
 197}
 198
 199static void dtt200u_fe_release(struct dvb_frontend* fe)
 200{
 201        struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
 202        kfree(state);
 203}
 204
 205static const struct dvb_frontend_ops dtt200u_fe_ops;
 206
 207struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
 208{
 209        struct dtt200u_fe_state* state = NULL;
 210
 211        /* allocate memory for the internal state */
 212        state = kzalloc(sizeof(struct dtt200u_fe_state), GFP_KERNEL);
 213        if (state == NULL)
 214                goto error;
 215
 216        deb_info("attaching frontend dtt200u\n");
 217
 218        state->d = d;
 219        mutex_init(&state->data_mutex);
 220
 221        memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
 222        state->frontend.demodulator_priv = state;
 223
 224        return &state->frontend;
 225error:
 226        return NULL;
 227}
 228
 229static const struct dvb_frontend_ops dtt200u_fe_ops = {
 230        .delsys = { SYS_DVBT },
 231        .info = {
 232                .name                   = "WideView USB DVB-T",
 233                .frequency_min          = 44250000,
 234                .frequency_max          = 867250000,
 235                .frequency_stepsize     = 250000,
 236                .caps = FE_CAN_INVERSION_AUTO |
 237                                FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
 238                                FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
 239                                FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
 240                                FE_CAN_TRANSMISSION_MODE_AUTO |
 241                                FE_CAN_GUARD_INTERVAL_AUTO |
 242                                FE_CAN_RECOVER |
 243                                FE_CAN_HIERARCHY_AUTO,
 244        },
 245
 246        .release = dtt200u_fe_release,
 247
 248        .init = dtt200u_fe_init,
 249        .sleep = dtt200u_fe_sleep,
 250
 251        .set_frontend = dtt200u_fe_set_frontend,
 252        .get_frontend = dtt200u_fe_get_frontend,
 253        .get_tune_settings = dtt200u_fe_get_tune_settings,
 254
 255        .read_status = dtt200u_fe_read_status,
 256        .read_ber = dtt200u_fe_read_ber,
 257        .read_signal_strength = dtt200u_fe_read_signal_strength,
 258        .read_snr = dtt200u_fe_read_snr,
 259        .read_ucblocks = dtt200u_fe_read_unc_blocks,
 260};
 261