Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cinergyT2-fe.c
Go to the documentation of this file.
1 /*
2  * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
3  *
4  * Copyright (C) 2007 Tomi Orava ([email protected])
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 <[email protected]> and
10  * Holger Waechtler <[email protected]>
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 
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) {
99  tps |= (1 << 0);
100  break;
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 
140  struct dvb_frontend fe;
141  struct dvb_usb_device *d;
142 };
143 
144 static int cinergyt2_fe_read_status(struct dvb_frontend *fe,
146 {
148  struct dvbt_get_status_msg result;
150  int ret;
151 
152  ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result,
153  sizeof(result), 0);
154  if (ret < 0)
155  return ret;
156 
157  *status = 0;
158 
159  if (0xffff - le16_to_cpu(result.gain) > 30)
160  *status |= FE_HAS_SIGNAL;
161  if (result.lock_bits & (1 << 6))
162  *status |= FE_HAS_LOCK;
163  if (result.lock_bits & (1 << 5))
164  *status |= FE_HAS_SYNC;
165  if (result.lock_bits & (1 << 4))
166  *status |= FE_HAS_CARRIER;
167  if (result.lock_bits & (1 << 1))
168  *status |= FE_HAS_VITERBI;
169 
170  if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
172  *status &= ~FE_HAS_LOCK;
173 
174  return 0;
175 }
176 
177 static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
178 {
179  struct cinergyt2_fe_state *state = fe->demodulator_priv;
180  struct dvbt_get_status_msg status;
181  char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
182  int ret;
183 
184  ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
185  sizeof(status), 0);
186  if (ret < 0)
187  return ret;
188 
189  *ber = le32_to_cpu(status.viterbi_error_rate);
190  return 0;
191 }
192 
193 static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
194 {
195  struct cinergyt2_fe_state *state = fe->demodulator_priv;
196  struct dvbt_get_status_msg status;
198  int ret;
199 
200  ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&status,
201  sizeof(status), 0);
202  if (ret < 0) {
203  err("cinergyt2_fe_read_unc_blocks() Failed! (Error=%d)\n",
204  ret);
205  return ret;
206  }
207  *unc = le32_to_cpu(status.uncorrected_block_count);
208  return 0;
209 }
210 
211 static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe,
212  u16 *strength)
213 {
214  struct cinergyt2_fe_state *state = fe->demodulator_priv;
215  struct dvbt_get_status_msg status;
216  char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
217  int ret;
218 
219  ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
220  sizeof(status), 0);
221  if (ret < 0) {
222  err("cinergyt2_fe_read_signal_strength() Failed!"
223  " (Error=%d)\n", ret);
224  return ret;
225  }
226  *strength = (0xffff - le16_to_cpu(status.gain));
227  return 0;
228 }
229 
230 static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
231 {
232  struct cinergyt2_fe_state *state = fe->demodulator_priv;
233  struct dvbt_get_status_msg status;
234  char cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS };
235  int ret;
236 
237  ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (char *)&status,
238  sizeof(status), 0);
239  if (ret < 0) {
240  err("cinergyt2_fe_read_snr() Failed! (Error=%d)\n", ret);
241  return ret;
242  }
243  *snr = (status.snr << 8) | status.snr;
244  return 0;
245 }
246 
247 static int cinergyt2_fe_init(struct dvb_frontend *fe)
248 {
249  return 0;
250 }
251 
252 static int cinergyt2_fe_sleep(struct dvb_frontend *fe)
253 {
254  deb_info("cinergyt2_fe_sleep() Called\n");
255  return 0;
256 }
257 
258 static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe,
259  struct dvb_frontend_tune_settings *tune)
260 {
261  tune->min_delay_ms = 800;
262  return 0;
263 }
264 
265 static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe)
266 {
267  struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
268  struct cinergyt2_fe_state *state = fe->demodulator_priv;
270  char result[2];
271  int err;
272 
274  param.tps = cpu_to_le16(compute_tps(fep));
275  param.freq = cpu_to_le32(fep->frequency / 1000);
276  param.flags = 0;
277 
278  switch (fep->bandwidth_hz) {
279  default:
280  case 8000000:
281  param.bandwidth = 8;
282  break;
283  case 7000000:
284  param.bandwidth = 7;
285  break;
286  case 6000000:
287  param.bandwidth = 6;
288  break;
289  }
290 
291  err = dvb_usb_generic_rw(state->d,
292  (char *)&param, sizeof(param),
293  result, sizeof(result), 0);
294  if (err < 0)
295  err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err);
296 
297  return (err < 0) ? err : 0;
298 }
299 
300 static void cinergyt2_fe_release(struct dvb_frontend *fe)
301 {
302  struct cinergyt2_fe_state *state = fe->demodulator_priv;
303  if (state != NULL)
304  kfree(state);
305 }
306 
307 static struct dvb_frontend_ops cinergyt2_fe_ops;
308 
310 {
311  struct cinergyt2_fe_state *s = kzalloc(sizeof(
312  struct cinergyt2_fe_state), GFP_KERNEL);
313  if (s == NULL)
314  return NULL;
315 
316  s->d = d;
317  memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops));
318  s->fe.demodulator_priv = s;
319  return &s->fe;
320 }
321 
322 
323 static struct dvb_frontend_ops cinergyt2_fe_ops = {
324  .delsys = { SYS_DVBT },
325  .info = {
326  .name = DRIVER_NAME,
327  .frequency_min = 174000000,
328  .frequency_max = 862000000,
329  .frequency_stepsize = 166667,
341  },
342 
343  .release = cinergyt2_fe_release,
344 
345  .init = cinergyt2_fe_init,
346  .sleep = cinergyt2_fe_sleep,
347 
348  .set_frontend = cinergyt2_fe_set_frontend,
349  .get_tune_settings = cinergyt2_fe_get_tune_settings,
350 
351  .read_status = cinergyt2_fe_read_status,
352  .read_ber = cinergyt2_fe_read_ber,
353  .read_signal_strength = cinergyt2_fe_read_signal_strength,
354  .read_snr = cinergyt2_fe_read_snr,
355  .read_ucblocks = cinergyt2_fe_read_unc_blocks,
356 };