Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
as102_fe.c
Go to the documentation of this file.
1 /*
2  * Abilis Systems Single DVB-T Receiver
3  * Copyright (C) 2008 Pierrick Hascoet <[email protected]>
4  * Copyright (C) 2010 Devin Heitmueller <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 #include "as102_drv.h"
21 #include "as10x_types.h"
22 #include "as10x_cmd.h"
23 
24 static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *dst,
25  struct as10x_tps *src);
26 
27 static void as102_fe_copy_tune_parameters(struct as10x_tune_args *dst,
29 
30 static int as102_fe_set_frontend(struct dvb_frontend *fe)
31 {
33  int ret = 0;
34  struct as102_dev_t *dev;
35  struct as10x_tune_args tune_args = { 0 };
36 
37  ENTER();
38 
39  dev = (struct as102_dev_t *) fe->tuner_priv;
40  if (dev == NULL)
41  return -ENODEV;
42 
43  if (mutex_lock_interruptible(&dev->bus_adap.lock))
44  return -EBUSY;
45 
46  as102_fe_copy_tune_parameters(&tune_args, p);
47 
48  /* send abilis command: SET_TUNE */
49  ret = as10x_cmd_set_tune(&dev->bus_adap, &tune_args);
50  if (ret != 0)
51  dprintk(debug, "as10x_cmd_set_tune failed. (err = %d)\n", ret);
52 
53  mutex_unlock(&dev->bus_adap.lock);
54 
55  LEAVE();
56  return (ret < 0) ? -EINVAL : 0;
57 }
58 
59 static int as102_fe_get_frontend(struct dvb_frontend *fe)
60 {
62  int ret = 0;
63  struct as102_dev_t *dev;
64  struct as10x_tps tps = { 0 };
65 
66  ENTER();
67 
68  dev = (struct as102_dev_t *) fe->tuner_priv;
69  if (dev == NULL)
70  return -EINVAL;
71 
72  if (mutex_lock_interruptible(&dev->bus_adap.lock))
73  return -EBUSY;
74 
75  /* send abilis command: GET_TPS */
76  ret = as10x_cmd_get_tps(&dev->bus_adap, &tps);
77 
78  if (ret == 0)
79  as10x_fe_copy_tps_parameters(p, &tps);
80 
81  mutex_unlock(&dev->bus_adap.lock);
82 
83  LEAVE();
84  return (ret < 0) ? -EINVAL : 0;
85 }
86 
87 static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
88  struct dvb_frontend_tune_settings *settings) {
89  ENTER();
90 
91 #if 0
92  dprintk(debug, "step_size = %d\n", settings->step_size);
93  dprintk(debug, "max_drift = %d\n", settings->max_drift);
94  dprintk(debug, "min_delay_ms = %d -> %d\n", settings->min_delay_ms,
95  1000);
96 #endif
97 
98  settings->min_delay_ms = 1000;
99 
100  LEAVE();
101  return 0;
102 }
103 
104 
105 static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
106 {
107  int ret = 0;
108  struct as102_dev_t *dev;
109  struct as10x_tune_status tstate = { 0 };
110 
111  ENTER();
112 
113  dev = (struct as102_dev_t *) fe->tuner_priv;
114  if (dev == NULL)
115  return -ENODEV;
116 
117  if (mutex_lock_interruptible(&dev->bus_adap.lock))
118  return -EBUSY;
119 
120  /* send abilis command: GET_TUNE_STATUS */
121  ret = as10x_cmd_get_tune_status(&dev->bus_adap, &tstate);
122  if (ret < 0) {
123  dprintk(debug, "as10x_cmd_get_tune_status failed (err = %d)\n",
124  ret);
125  goto out;
126  }
127 
128  dev->signal_strength = tstate.signal_strength;
129  dev->ber = tstate.BER;
130 
131  switch (tstate.tune_state) {
133  *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
134  break;
137  break;
140  FE_HAS_LOCK;
141  break;
142  default:
143  *status = TUNE_STATUS_NOT_TUNED;
144  }
145 
146  dprintk(debug, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
147  tstate.tune_state, tstate.signal_strength,
148  tstate.PER, tstate.BER);
149 
150  if (*status & FE_HAS_LOCK) {
152  (struct as10x_demod_stats *) &dev->demod_stats) < 0) {
153  memset(&dev->demod_stats, 0, sizeof(dev->demod_stats));
154  dprintk(debug, "as10x_cmd_get_demod_stats failed "
155  "(probably not tuned)\n");
156  } else {
157  dprintk(debug,
158  "demod status: fc: 0x%08x, bad fc: 0x%08x, "
159  "bytes corrected: 0x%08x , MER: 0x%04x\n",
160  dev->demod_stats.frame_count,
161  dev->demod_stats.bad_frame_count,
162  dev->demod_stats.bytes_fixed_by_rs,
163  dev->demod_stats.mer);
164  }
165  } else {
166  memset(&dev->demod_stats, 0, sizeof(dev->demod_stats));
167  }
168 
169 out:
170  mutex_unlock(&dev->bus_adap.lock);
171  LEAVE();
172  return ret;
173 }
174 
175 /*
176  * Note:
177  * - in AS102 SNR=MER
178  * - the SNR will be returned in linear terms, i.e. not in dB
179  * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB
180  * - the accuracy is >2dB for SNR values outside this range
181  */
182 static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
183 {
184  struct as102_dev_t *dev;
185 
186  ENTER();
187 
188  dev = (struct as102_dev_t *) fe->tuner_priv;
189  if (dev == NULL)
190  return -ENODEV;
191 
192  *snr = dev->demod_stats.mer;
193 
194  LEAVE();
195  return 0;
196 }
197 
198 static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
199 {
200  struct as102_dev_t *dev;
201 
202  ENTER();
203 
204  dev = (struct as102_dev_t *) fe->tuner_priv;
205  if (dev == NULL)
206  return -ENODEV;
207 
208  *ber = dev->ber;
209 
210  LEAVE();
211  return 0;
212 }
213 
214 static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
215  u16 *strength)
216 {
217  struct as102_dev_t *dev;
218 
219  ENTER();
220 
221  dev = (struct as102_dev_t *) fe->tuner_priv;
222  if (dev == NULL)
223  return -ENODEV;
224 
225  *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2);
226 
227  LEAVE();
228  return 0;
229 }
230 
231 static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
232 {
233  struct as102_dev_t *dev;
234 
235  ENTER();
236 
237  dev = (struct as102_dev_t *) fe->tuner_priv;
238  if (dev == NULL)
239  return -ENODEV;
240 
241  if (dev->demod_stats.has_started)
242  *ucblocks = dev->demod_stats.bad_frame_count;
243  else
244  *ucblocks = 0;
245 
246  LEAVE();
247  return 0;
248 }
249 
250 static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
251 {
252  struct as102_dev_t *dev;
253  int ret;
254 
255  ENTER();
256 
257  dev = (struct as102_dev_t *) fe->tuner_priv;
258  if (dev == NULL)
259  return -ENODEV;
260 
261  if (mutex_lock_interruptible(&dev->bus_adap.lock))
262  return -EBUSY;
263 
264  if (acquire) {
265  if (elna_enable)
267 
268  ret = as10x_cmd_turn_on(&dev->bus_adap);
269  } else {
270  ret = as10x_cmd_turn_off(&dev->bus_adap);
271  }
272 
273  mutex_unlock(&dev->bus_adap.lock);
274 
275  LEAVE();
276  return ret;
277 }
278 
279 static struct dvb_frontend_ops as102_fe_ops = {
280  .delsys = { SYS_DVBT },
281  .info = {
282  .name = "Unknown AS102 device",
283  .frequency_min = 174000000,
284  .frequency_max = 862000000,
285  .frequency_stepsize = 166667,
286  .caps = FE_CAN_INVERSION_AUTO
296  },
297 
298  .set_frontend = as102_fe_set_frontend,
299  .get_frontend = as102_fe_get_frontend,
300  .get_tune_settings = as102_fe_get_tune_settings,
301 
302  .read_status = as102_fe_read_status,
303  .read_snr = as102_fe_read_snr,
304  .read_ber = as102_fe_read_ber,
305  .read_signal_strength = as102_fe_read_signal_strength,
306  .read_ucblocks = as102_fe_read_ucblocks,
307  .ts_bus_ctrl = as102_fe_ts_bus_ctrl,
308 };
309 
311 {
312  /* unregister frontend */
314 
315  /* detach frontend */
317 
318  return 0;
319 }
320 
321 int as102_dvb_register_fe(struct as102_dev_t *as102_dev,
322  struct dvb_frontend *dvb_fe)
323 {
324  int errno;
325  struct dvb_adapter *dvb_adap;
326 
327  if (as102_dev == NULL)
328  return -EINVAL;
329 
330  /* extract dvb_adapter */
331  dvb_adap = &as102_dev->dvb_adap;
332 
333  /* init frontend callback ops */
334  memcpy(&dvb_fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
335  strncpy(dvb_fe->ops.info.name, as102_dev->name,
336  sizeof(dvb_fe->ops.info.name));
337 
338  /* register dvb frontend */
339  errno = dvb_register_frontend(dvb_adap, dvb_fe);
340  if (errno == 0)
341  dvb_fe->tuner_priv = as102_dev;
342 
343  return errno;
344 }
345 
346 static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties *fe_tps,
347  struct as10x_tps *as10x_tps)
348 {
349 
350  /* extract constellation */
351  switch (as10x_tps->modulation) {
352  case CONST_QPSK:
353  fe_tps->modulation = QPSK;
354  break;
355  case CONST_QAM16:
356  fe_tps->modulation = QAM_16;
357  break;
358  case CONST_QAM64:
359  fe_tps->modulation = QAM_64;
360  break;
361  }
362 
363  /* extract hierarchy */
364  switch (as10x_tps->hierarchy) {
365  case HIER_NONE:
366  fe_tps->hierarchy = HIERARCHY_NONE;
367  break;
368  case HIER_ALPHA_1:
369  fe_tps->hierarchy = HIERARCHY_1;
370  break;
371  case HIER_ALPHA_2:
372  fe_tps->hierarchy = HIERARCHY_2;
373  break;
374  case HIER_ALPHA_4:
375  fe_tps->hierarchy = HIERARCHY_4;
376  break;
377  }
378 
379  /* extract code rate HP */
380  switch (as10x_tps->code_rate_HP) {
381  case CODE_RATE_1_2:
382  fe_tps->code_rate_HP = FEC_1_2;
383  break;
384  case CODE_RATE_2_3:
385  fe_tps->code_rate_HP = FEC_2_3;
386  break;
387  case CODE_RATE_3_4:
388  fe_tps->code_rate_HP = FEC_3_4;
389  break;
390  case CODE_RATE_5_6:
391  fe_tps->code_rate_HP = FEC_5_6;
392  break;
393  case CODE_RATE_7_8:
394  fe_tps->code_rate_HP = FEC_7_8;
395  break;
396  }
397 
398  /* extract code rate LP */
399  switch (as10x_tps->code_rate_LP) {
400  case CODE_RATE_1_2:
401  fe_tps->code_rate_LP = FEC_1_2;
402  break;
403  case CODE_RATE_2_3:
404  fe_tps->code_rate_LP = FEC_2_3;
405  break;
406  case CODE_RATE_3_4:
407  fe_tps->code_rate_LP = FEC_3_4;
408  break;
409  case CODE_RATE_5_6:
410  fe_tps->code_rate_LP = FEC_5_6;
411  break;
412  case CODE_RATE_7_8:
413  fe_tps->code_rate_LP = FEC_7_8;
414  break;
415  }
416 
417  /* extract guard interval */
418  switch (as10x_tps->guard_interval) {
419  case GUARD_INT_1_32:
421  break;
422  case GUARD_INT_1_16:
424  break;
425  case GUARD_INT_1_8:
427  break;
428  case GUARD_INT_1_4:
430  break;
431  }
432 
433  /* extract transmission mode */
434  switch (as10x_tps->transmission_mode) {
435  case TRANS_MODE_2K:
437  break;
438  case TRANS_MODE_8K:
440  break;
441  }
442 }
443 
444 static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg)
445 {
446  uint8_t c;
447 
448  switch (arg) {
449  case FEC_1_2:
450  c = CODE_RATE_1_2;
451  break;
452  case FEC_2_3:
453  c = CODE_RATE_2_3;
454  break;
455  case FEC_3_4:
456  c = CODE_RATE_3_4;
457  break;
458  case FEC_5_6:
459  c = CODE_RATE_5_6;
460  break;
461  case FEC_7_8:
462  c = CODE_RATE_7_8;
463  break;
464  default:
465  c = CODE_RATE_UNKNOWN;
466  break;
467  }
468 
469  return c;
470 }
471 
472 static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
474 {
475 
476  /* set frequency */
477  tune_args->freq = params->frequency / 1000;
478 
479  /* fix interleaving_mode */
480  tune_args->interleaving_mode = INTLV_NATIVE;
481 
482  switch (params->bandwidth_hz) {
483  case 8000000:
484  tune_args->bandwidth = BW_8_MHZ;
485  break;
486  case 7000000:
487  tune_args->bandwidth = BW_7_MHZ;
488  break;
489  case 6000000:
490  tune_args->bandwidth = BW_6_MHZ;
491  break;
492  default:
493  tune_args->bandwidth = BW_8_MHZ;
494  }
495 
496  switch (params->guard_interval) {
497  case GUARD_INTERVAL_1_32:
498  tune_args->guard_interval = GUARD_INT_1_32;
499  break;
500  case GUARD_INTERVAL_1_16:
501  tune_args->guard_interval = GUARD_INT_1_16;
502  break;
503  case GUARD_INTERVAL_1_8:
504  tune_args->guard_interval = GUARD_INT_1_8;
505  break;
506  case GUARD_INTERVAL_1_4:
507  tune_args->guard_interval = GUARD_INT_1_4;
508  break;
509  case GUARD_INTERVAL_AUTO:
510  default:
511  tune_args->guard_interval = GUARD_UNKNOWN;
512  break;
513  }
514 
515  switch (params->modulation) {
516  case QPSK:
517  tune_args->modulation = CONST_QPSK;
518  break;
519  case QAM_16:
520  tune_args->modulation = CONST_QAM16;
521  break;
522  case QAM_64:
523  tune_args->modulation = CONST_QAM64;
524  break;
525  default:
526  tune_args->modulation = CONST_UNKNOWN;
527  break;
528  }
529 
530  switch (params->transmission_mode) {
532  tune_args->transmission_mode = TRANS_MODE_2K;
533  break;
535  tune_args->transmission_mode = TRANS_MODE_8K;
536  break;
537  default:
539  }
540 
541  switch (params->hierarchy) {
542  case HIERARCHY_NONE:
543  tune_args->hierarchy = HIER_NONE;
544  break;
545  case HIERARCHY_1:
546  tune_args->hierarchy = HIER_ALPHA_1;
547  break;
548  case HIERARCHY_2:
549  tune_args->hierarchy = HIER_ALPHA_2;
550  break;
551  case HIERARCHY_4:
552  tune_args->hierarchy = HIER_ALPHA_4;
553  break;
554  case HIERARCHY_AUTO:
555  tune_args->hierarchy = HIER_UNKNOWN;
556  break;
557  }
558 
559  dprintk(debug, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n",
560  params->frequency,
561  tune_args->bandwidth,
562  tune_args->guard_interval);
563 
564  /*
565  * Detect a hierarchy selection
566  * if HP/LP are both set to FEC_NONE, HP will be selected.
567  */
568  if ((tune_args->hierarchy != HIER_NONE) &&
569  ((params->code_rate_LP == FEC_NONE) ||
570  (params->code_rate_HP == FEC_NONE))) {
571 
572  if (params->code_rate_LP == FEC_NONE) {
573  tune_args->hier_select = HIER_HIGH_PRIORITY;
574  tune_args->code_rate =
575  as102_fe_get_code_rate(params->code_rate_HP);
576  }
577 
578  if (params->code_rate_HP == FEC_NONE) {
579  tune_args->hier_select = HIER_LOW_PRIORITY;
580  tune_args->code_rate =
581  as102_fe_get_code_rate(params->code_rate_LP);
582  }
583 
584  dprintk(debug, "\thierarchy: 0x%02x "
585  "selected: %s code_rate_%s: 0x%02x\n",
586  tune_args->hierarchy,
587  tune_args->hier_select == HIER_HIGH_PRIORITY ?
588  "HP" : "LP",
589  tune_args->hier_select == HIER_HIGH_PRIORITY ?
590  "HP" : "LP",
591  tune_args->code_rate);
592  } else {
593  tune_args->code_rate =
594  as102_fe_get_code_rate(params->code_rate_HP);
595  }
596 }