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 43 static 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 139 struct cinergyt2_fe_state { 140 struct dvb_frontend fe; 141 struct dvb_usb_device *d; 142 143 unsigned char data[64]; 144 struct mutex data_mutex; 145 146 struct dvbt_get_status_msg status; 147 }; 148 149 static int cinergyt2_fe_read_status(struct dvb_frontend *fe, 150 enum fe_status *status) 151 { 152 struct cinergyt2_fe_state *state = fe->demodulator_priv; 153 int ret; 154 155 mutex_lock(&state->data_mutex); 156 state->data[0] = CINERGYT2_EP1_GET_TUNER_STATUS; 157 158 ret = dvb_usb_generic_rw(state->d, state->data, 1, 159 state->data, sizeof(state->status), 0); 160 if (!ret) 161 memcpy(&state->status, state->data, sizeof(state->status)); 162 mutex_unlock(&state->data_mutex); 163 164 if (ret < 0) 165 return ret; 166 167 *status = 0; 168 169 if (0xffff - le16_to_cpu(state->status.gain) > 30) 170 *status |= FE_HAS_SIGNAL; 171 if (state->status.lock_bits & (1 << 6)) 172 *status |= FE_HAS_LOCK; 173 if (state->status.lock_bits & (1 << 5)) 174 *status |= FE_HAS_SYNC; 175 if (state->status.lock_bits & (1 << 4)) 176 *status |= FE_HAS_CARRIER; 177 if (state->status.lock_bits & (1 << 1)) 178 *status |= FE_HAS_VITERBI; 179 180 if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != 181 (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) 182 *status &= ~FE_HAS_LOCK; 183 184 return 0; 185 } 186 187 static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) 188 { 189 struct cinergyt2_fe_state *state = fe->demodulator_priv; 190 191 *ber = le32_to_cpu(state->status.viterbi_error_rate); 192 return 0; 193 } 194 195 static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) 196 { 197 struct cinergyt2_fe_state *state = fe->demodulator_priv; 198 199 *unc = le32_to_cpu(state->status.uncorrected_block_count); 200 return 0; 201 } 202 203 static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, 204 u16 *strength) 205 { 206 struct cinergyt2_fe_state *state = fe->demodulator_priv; 207 208 *strength = (0xffff - le16_to_cpu(state->status.gain)); 209 return 0; 210 } 211 212 static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) 213 { 214 struct cinergyt2_fe_state *state = fe->demodulator_priv; 215 216 *snr = (state->status.snr << 8) | state->status.snr; 217 return 0; 218 } 219 220 static int cinergyt2_fe_init(struct dvb_frontend *fe) 221 { 222 return 0; 223 } 224 225 static int cinergyt2_fe_sleep(struct dvb_frontend *fe) 226 { 227 deb_info("cinergyt2_fe_sleep() Called\n"); 228 return 0; 229 } 230 231 static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, 232 struct dvb_frontend_tune_settings *tune) 233 { 234 tune->min_delay_ms = 800; 235 return 0; 236 } 237 238 static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) 239 { 240 struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 241 struct cinergyt2_fe_state *state = fe->demodulator_priv; 242 struct dvbt_set_parameters_msg *param; 243 int err; 244 245 mutex_lock(&state->data_mutex); 246 247 param = (void *)state->data; 248 param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; 249 param->tps = cpu_to_le16(compute_tps(fep)); 250 param->freq = cpu_to_le32(fep->frequency / 1000); 251 param->flags = 0; 252 253 switch (fep->bandwidth_hz) { 254 default: 255 case 8000000: 256 param->bandwidth = 8; 257 break; 258 case 7000000: 259 param->bandwidth = 7; 260 break; 261 case 6000000: 262 param->bandwidth = 6; 263 break; 264 } 265 266 err = dvb_usb_generic_rw(state->d, state->data, sizeof(*param), 267 state->data, 2, 0); 268 if (err < 0) 269 err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); 270 271 mutex_unlock(&state->data_mutex); 272 return (err < 0) ? err : 0; 273 } 274 275 static void cinergyt2_fe_release(struct dvb_frontend *fe) 276 { 277 struct cinergyt2_fe_state *state = fe->demodulator_priv; 278 kfree(state); 279 } 280 281 static struct dvb_frontend_ops cinergyt2_fe_ops; 282 283 struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) 284 { 285 struct cinergyt2_fe_state *s = kzalloc(sizeof( 286 struct cinergyt2_fe_state), GFP_KERNEL); 287 if (s == NULL) 288 return NULL; 289 290 s->d = d; 291 memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); 292 s->fe.demodulator_priv = s; 293 mutex_init(&s->data_mutex); 294 return &s->fe; 295 } 296 297 298 static struct dvb_frontend_ops cinergyt2_fe_ops = { 299 .delsys = { SYS_DVBT }, 300 .info = { 301 .name = DRIVER_NAME, 302 .frequency_min = 174000000, 303 .frequency_max = 862000000, 304 .frequency_stepsize = 166667, 305 .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 306 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 307 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 308 | FE_CAN_FEC_AUTO | FE_CAN_QPSK 309 | FE_CAN_QAM_16 | FE_CAN_QAM_64 310 | FE_CAN_QAM_AUTO 311 | FE_CAN_TRANSMISSION_MODE_AUTO 312 | FE_CAN_GUARD_INTERVAL_AUTO 313 | FE_CAN_HIERARCHY_AUTO 314 | FE_CAN_RECOVER 315 | FE_CAN_MUTE_TS 316 }, 317 318 .release = cinergyt2_fe_release, 319 320 .init = cinergyt2_fe_init, 321 .sleep = cinergyt2_fe_sleep, 322 323 .set_frontend = cinergyt2_fe_set_frontend, 324 .get_tune_settings = cinergyt2_fe_get_tune_settings, 325 326 .read_status = cinergyt2_fe_read_status, 327 .read_ber = cinergyt2_fe_read_ber, 328 .read_signal_strength = cinergyt2_fe_read_signal_strength, 329 .read_snr = cinergyt2_fe_read_snr, 330 .read_ucblocks = cinergyt2_fe_read_unc_blocks, 331 }; 332