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 14 struct 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 26 static 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 59 static 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 75 static 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 91 static 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 107 static 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 123 static 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 137 static int dtt200u_fe_sleep(struct dvb_frontend* fe) 138 { 139 return dtt200u_fe_init(fe); 140 } 141 142 static 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 150 static 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 185 ret: 186 mutex_unlock(&state->data_mutex); 187 return ret; 188 } 189 190 static 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 199 static 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 205 static struct dvb_frontend_ops dtt200u_fe_ops; 206 207 struct 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; 225 error: 226 return NULL; 227 } 228 229 static 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