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