1 /*
2 * Copyright (c) 2011-2016 - Mauro Carvalho Chehab
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation version 2.1 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 * Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
17 *
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <strings.h> /* strcasecmp */
24
25 #include "dvb-fe-priv.h"
26 #include <libdvbv5/dvb-v5-std.h>
27
28 #ifdef ENABLE_NLS
29 # include "gettext.h"
30 # include <libintl.h>
31 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
32
33 #else
34 # define _(string) string
35 #endif
36
37 # define N_(string) string
38
39 struct dvbsat_freqrange_priv {
40 unsigned low, high, int_freq, rangeswitch;
41 enum dvb_sat_polarization pol;
42 };
43
44 struct dvb_sat_lnb_priv {
45 struct dvb_sat_lnb desc;
46
47 /* Private members used internally */
48 struct dvbsat_freqrange_priv freqrange[4];
49 };
50
51 static const struct dvb_sat_lnb_priv lnb_array[] = {
52 {
53 .desc = {
54 .name = N_("Astra 19.2E, European Universal Ku (extended)"),
55 .alias = "EXTENDED",
56 // Legacy fields - kept just to avoid API/ABI breakages
57 .lowfreq = 9750,
58 .highfreq = 10600,
59 .rangeswitch = 11700,
60 .freqrange = {
61 { 10700, 11700 },
62 { 11700, 12750 },
63 },
64 },
65 .freqrange = {
66 { 10700, 11700, 9750, 11700},
67 { 11700, 12750, 10600, 0 },
68 }
69 }, {
70 .desc = {
71 .name = N_("Old European Universal. Nowadays mostly replaced by Astra 19.2E"),
72 .alias = "UNIVERSAL",
73 // Legacy fields - kept just to avoid API/ABI breakages
74 .lowfreq = 9750,
75 .highfreq = 10600,
76 .rangeswitch = 11700,
77 .freqrange = {
78 { 10800, 11800 },
79 { 11600, 12700 },
80 },
81 },
82 .freqrange = {
83 { 10800, 11800, 9750, 11700 },
84 { 11600, 12700, 10600, 0 },
85 }
86 }, {
87 .desc = {
88 .name = N_("Expressvu, North America"),
89 .alias = "DBS",
90 // Legacy fields - kept just to avoid API/ABI breakages
91 .lowfreq = 11250,
92 .freqrange = {
93 { 12200, 12700 }
94 },
95 },
96 .freqrange = {
97 { 12200, 12700, 11250 }
98 }
99 }, {
100 .desc = {
101 .name = N_("Standard"),
102 .alias = "STANDARD",
103 // Legacy fields - kept just to avoid API/ABI breakages
104 .lowfreq = 10000,
105 .freqrange = {
106 { 10945, 11450 }
107 },
108 },
109 .freqrange = {
110 { 10945, 11450, 10000, 0 }
111 },
112 }, {
113 .desc = {
114 .name = N_("L10700"),
115 .alias = "L10700",
116 // Legacy fields - kept just to avoid API/ABI breakages
117 .lowfreq = 10700,
118 .freqrange = {
119 { 11750, 12750 }
120 },
121 },
122 .freqrange = {
123 { 11750, 12750, 10700, 0 }
124 },
125 }, {
126 .desc = {
127 .name = N_("L10750"),
128 .alias = "L10750",
129 // Legacy fields - kept just to avoid API/ABI breakages
130 .lowfreq = 10750,
131 .freqrange = {
132 { 11700, 12200 }
133 },
134 },
135 .freqrange = {
136 { 11700, 12200, 10750, 0 }
137 },
138 }, {
139 .desc = {
140 .name = N_("L11300"),
141 .alias = "L11300",
142 // Legacy fields - kept just to avoid API/ABI breakages
143 .lowfreq = 11300,
144 .freqrange = {
145 { 12250, 12750 }
146 },
147 },
148 .freqrange = {
149 { 12250, 12750, 11300, 0 }
150 },
151 }, {
152 .desc = {
153 .name = N_("Astra"),
154 .alias = "ENHANCED",
155 // Legacy fields - kept just to avoid API/ABI breakages
156 .lowfreq = 9750,
157 .freqrange = {
158 { 10700, 11700 }
159 },
160 },
161 .freqrange = {
162 { 10700, 11700, 9750, 0 }
163 },
164 }, {
165 .desc = {
166 .name = N_("Invacom QPH-031"),
167 .alias = "QPH031",
168 // Legacy fields - kept just to avoid API/ABI breakages
169 .lowfreq = 10750,
170 .highfreq = 11250,
171 .rangeswitch = 12200,
172 .freqrange = {
173 { 11700, 12200 },
174 { 12200, 12700 },
175 },
176 },
177 // Note: This LNBf can accept both V/H and L/R polarization
178 // on ports 1 and 3, V is 12V and H is 19V
179 // on ports 2 and 4, R is 12V and L is 19V
180 // This is the same as what's done for Universal LNBf, so,
181 // we don't need any special logic here to handle this special
182 // case.
183 .freqrange = {
184 { 11700, 12200, 10750, 12200 },
185 { 12200, 12700, 11250, 0 },
186 },
187 }, {
188 .desc = {
189 .name = N_("Big Dish - Monopoint LNBf"),
190 .alias = "C-BAND",
191 // Legacy fields - kept just to avoid API/ABI breakages
192 .lowfreq = 5150,
193 .freqrange = {
194 { 3700, 4200 }
195 },
196 },
197 .freqrange = {
198 { 3700, 4200, 5150, 0 }
199 },
200 }, {
201 .desc = {
202 .name = N_("Big Dish - Multipoint LNBf"),
203 .alias = "C-MULT",
204 // Legacy fields - kept just to avoid API/ABI breakages
205 .lowfreq = 5150,
206 .highfreq = 5750,
207 .freqrange = {
208 { 3700, 4200 }
209 },
210 },
211 .freqrange = {
212 { 3700, 4200, 5150, 0, POLARIZATION_R },
213 { 3700, 4200, 5750, 0, POLARIZATION_L }
214 },
215 }, {
216 .desc = {
217 .name = N_("DishPro LNBf"),
218 .alias = "DISHPRO",
219 // Legacy fields - kept just to avoid API/ABI breakages
220 .lowfreq = 11250,
221 .highfreq = 14350,
222 .freqrange = {
223 { 12200, 12700 }
224 },
225 },
226 .freqrange = {
227 { 12200, 12700, 11250, 0, POLARIZATION_V },
228 { 12200, 12700, 14350, 0, POLARIZATION_H }
229 }
230 }, {
231 .desc = {
232 .name = N_("Japan 110BS/CS LNBf"),
233 .alias = "110BS",
234 // Legacy fields - kept just to avoid API/ABI breakages
235 .lowfreq = 10678,
236 .freqrange = {
237 { 11710, 12751 }
238 },
239 },
240 .freqrange = {
241 { 11710, 12751, 10678, 0 }
242 }
243 }, {
244 .desc = {
245 .name = N_("BrasilSat Stacked"),
246 .alias = "STACKED-BRASILSAT",
247 // Legacy fields - kept just to avoid API/ABI breakages
248 .lowfreq = 9710,
249 .highfreq = 9750,
250 .freqrange = {
251 { 10700, 11700 },
252 },
253 },
254 .freqrange = {
255 { 10700, 11700, 9710, 0, POLARIZATION_H },
256 { 10700, 11700, 9750, 0, POLARIZATION_H },
257 },
258 }, {
259 .desc = {
260 .name = N_("BrasilSat Oi"),
261 .alias = "OI-BRASILSAT",
262 // Legacy fields - kept just to avoid API/ABI breakages
263 .lowfreq = 10000,
264 .highfreq = 10445,
265 .rangeswitch = 11700,
266 .freqrange = {
267 { 10950, 11200 },
268 { 11800, 12200 },
269 },
270 },
271 .freqrange = {
272 { 10950, 11200, 10000, 11700 },
273 { 11800, 12200, 10445, 0 },
274 }
275 }, {
276 .desc = {
277 .name = N_("BrasilSat Amazonas 1/2 - 3 Oscilators"),
278 .alias = "AMAZONAS",
279 // No legacy fields - as old API doesn't allow 3 LO
280 },
281 .freqrange = {
282 { 11037, 11450, 9670, 0, POLARIZATION_V },
283 { 11770, 12070, 9922, 0, POLARIZATION_H },
284 { 10950, 11280, 10000, 0, POLARIZATION_H },
285 },
286 }, {
287 .desc = {
288 .name = N_("BrasilSat Amazonas 1/2 - 2 Oscilators"),
289 .alias = "AMAZONAS",
290 // No legacy fields - as old API doesn't allow 3 ranges
291 },
292 .freqrange = {
293 { 11037, 11360, 9670, 0, POLARIZATION_V },
294 { 11780, 12150, 10000, 0, POLARIZATION_H },
295 { 10950, 11280, 10000, 0, POLARIZATION_H },
296 },
297 }, {
298 .desc = {
299 .name = N_("BrasilSat custom GVT"),
300 .alias = "GVT-BRASILSAT",
301 // No legacy fields - as old API doesn't allow 4 LO
302 },
303 .freqrange = {
304 { 11010.5, 11067.5, 12860, 0, POLARIZATION_V },
305 { 11704.0, 11941.0, 13435, 0, POLARIZATION_V },
306 { 10962.5, 11199.5, 13112, 0, POLARIZATION_H },
307 { 11704.0, 12188.0, 13138, 0, POLARIZATION_H },
308 },
309 },
310 };
311
dvb_sat_search_lnb(const char * name)312 int dvb_sat_search_lnb(const char *name)
313 {
314 int i = 0;
315
316 for (i = 0; i < ARRAY_SIZE(lnb_array); i++) {
317 if (!strcasecmp(name, lnb_array[i].desc.alias))
318 return i;
319 }
320 return -1;
321 }
322
323 static char *pol_name[] = {
324 [POLARIZATION_OFF] = N_("Freqs : "),
325 [POLARIZATION_H] = N_("Horizontal: "),
326 [POLARIZATION_V] = N_("Vertical : "),
327 [POLARIZATION_L] = N_("Left : "),
328 [POLARIZATION_R] = N_("Right : "),
329 };
330
dvb_print_lnb(int i)331 int dvb_print_lnb(int i)
332 {
333 int j;
334
335 if (i < 0 || i >= ARRAY_SIZE(lnb_array))
336 return -1;
337
338 printf("%s\n\t%s%s\n", lnb_array[i].desc.alias, dvb_sat_get_lnb_name(i),
339 lnb_array[i].freqrange[0].pol ? _(" (bandstacking)") : "");
340
341 for (j = 0; j < ARRAY_SIZE(lnb_array[i].freqrange) && lnb_array[i].freqrange[j].low; j++) {
342 printf(_("\t%s%d to %d MHz, LO: %d MHz\n"),
343 _(pol_name[lnb_array[i].freqrange[j].pol]),
344 lnb_array[i].freqrange[j].low,
345 lnb_array[i].freqrange[j].high,
346 lnb_array[i].freqrange[j].int_freq);
347 }
348
349 return 0;
350 }
351
dvb_print_all_lnb(void)352 void dvb_print_all_lnb(void)
353 {
354 int i;
355
356 for (i = 0; i < ARRAY_SIZE(lnb_array); i++) {
357 dvb_print_lnb(i);
358 printf("\n");
359 }
360 }
361
dvb_sat_get_lnb(int i)362 const struct dvb_sat_lnb *dvb_sat_get_lnb(int i)
363 {
364 if (i < 0 || i >= ARRAY_SIZE(lnb_array))
365 return NULL;
366
367 return (void *)&lnb_array[i];
368 }
369
dvb_sat_get_lnb_name(int i)370 const char *dvb_sat_get_lnb_name(int i)
371 {
372 if (i < 0 || i >= ARRAY_SIZE(lnb_array))
373 return NULL;
374
375 return _(lnb_array[i].desc.name);
376 }
377
378
379 /*
380 * DVB satellite Diseqc specifics
381 * According with:
382 * http://www.eutelsat.com/satellites/pdf/Diseqc/Reference%20docs/bus_spec.pdf
383 * http://www.eutelsat.com/satellites/pdf/Diseqc/associated%20docs/applic_info_turner-receiver.pdf
384 */
385
386 struct diseqc_cmd {
387 int len;
388 union {
389 unsigned char msg[6];
390 struct {
391 unsigned char framing;
392 unsigned char address;
393 unsigned char command;
394 unsigned char data0;
395 unsigned char data1;
396 unsigned char data2;
397 };
398 };
399 };
400
401 enum diseqc_type {
402 DISEQC_BROADCAST,
403 DISEQC_BROADCAST_LNB_SWITCHER_SMATV,
404 DISEQC_LNB,
405 DISEQC_LNB_WITH_LOOP_SWITCH,
406 DISEQC_SWITCHER,
407 DISEQC_SWITHCER_WITH_LOOP,
408 DISEQC_SMATV,
409 DISEQC_ANY_POLARISER,
410 DISEQC_LINEAR_POLARISER,
411 DISEQC_ANY_POSITIONER,
412 DISEQC_AZIMUTH_POSITIONER,
413 DISEQC_ELEVATON_POSITIONER,
414 DISEQC_ANY_INSTALLER_AID,
415 DISEQC_SIGNAL_STRENGH_ANALOGUE_VAL,
416 DISEQC_ANY_INTELLIGENT_SLAVE,
417 DISEQC_SUBSCRIBER_HEADENDS,
418 };
419
420 static int diseqc_addr[] = {
421 [DISEQC_BROADCAST] = 0x00,
422 [DISEQC_BROADCAST_LNB_SWITCHER_SMATV] = 0x10,
423 [DISEQC_LNB] = 0x11,
424 [DISEQC_LNB_WITH_LOOP_SWITCH] = 0x12,
425 [DISEQC_SWITCHER] = 0x14,
426 [DISEQC_SWITHCER_WITH_LOOP] = 0x15,
427 [DISEQC_SMATV] = 0x18,
428 [DISEQC_ANY_POLARISER] = 0x20,
429 [DISEQC_LINEAR_POLARISER] = 0x21,
430 [DISEQC_ANY_POSITIONER] = 0x30,
431 [DISEQC_AZIMUTH_POSITIONER] = 0x31,
432 [DISEQC_ELEVATON_POSITIONER] = 0x32,
433 [DISEQC_ANY_INSTALLER_AID] = 0x40,
434 [DISEQC_SIGNAL_STRENGH_ANALOGUE_VAL] = 0x41,
435 [DISEQC_ANY_INTELLIGENT_SLAVE] = 0x70,
436 [DISEQC_SUBSCRIBER_HEADENDS] = 0x71,
437 };
438
dvbsat_diseqc_prep_frame_addr(struct diseqc_cmd * cmd,enum diseqc_type type,int reply,int repeat)439 static void dvbsat_diseqc_prep_frame_addr(struct diseqc_cmd *cmd,
440 enum diseqc_type type,
441 int reply,
442 int repeat)
443 {
444 cmd->framing = 0xe0; /* First four bits are always 1110 */
445 if (reply)
446 cmd->framing |=0x02;
447 if (repeat)
448 cmd->framing |=1;
449
450 cmd->address = diseqc_addr[type];
451 }
452
453 //struct dvb_v5_fe_parms *parms; // legacy code, used for parms->fd, FIXME anyway
454
455 /* Inputs are numbered from 1 to 16, according with the spec */
dvbsat_diseqc_write_to_port_group(struct dvb_v5_fe_parms_priv * parms,struct diseqc_cmd * cmd,int high_band,int pol_v,int sat_number)456 static int dvbsat_diseqc_write_to_port_group(struct dvb_v5_fe_parms_priv *parms,
457 struct diseqc_cmd *cmd,
458 int high_band,
459 int pol_v,
460 int sat_number)
461 {
462 dvbsat_diseqc_prep_frame_addr(cmd,
463 DISEQC_BROADCAST_LNB_SWITCHER_SMATV,
464 0, 0);
465
466 cmd->command = 0x38; /* Write to Port group 0 (Committed switches) */
467 cmd->len = 4;
468
469 /* Fill the 4 bits for the "input" select */
470 cmd->data0 = 0xf0;
471 cmd->data0 |= high_band;
472 cmd->data0 |= pol_v ? 0 : 2;
473 /* Instead of using position/option, use a number from 0 to 3 */
474 cmd->data0 |= (sat_number & 0x3) << 2;
475
476 return dvb_fe_diseqc_cmd(&parms->p, cmd->len, cmd->msg);
477 }
478
dvbsat_scr_odu_channel_change(struct dvb_v5_fe_parms_priv * parms,struct diseqc_cmd * cmd,int high_band,int pol_v,int sat_number,uint16_t t)479 static int dvbsat_scr_odu_channel_change(struct dvb_v5_fe_parms_priv *parms,
480 struct diseqc_cmd *cmd,
481 int high_band,
482 int pol_v,
483 int sat_number,
484 uint16_t t)
485 {
486 int pos_b;
487
488 dvbsat_diseqc_prep_frame_addr(cmd,
489 DISEQC_BROADCAST_LNB_SWITCHER_SMATV,
490 0, 0);
491
492 cmd->command = 0x5a; /* ODU Channel Change */
493 cmd->len = 5;
494
495 /* Fill the tuning parameter */
496 cmd->data0 = (t >> 8) & 0x03;
497 cmd->data1 = t & 0xff;
498
499 /* Fill the satelite number - highest bit is for pos A/pos B */
500 cmd->data0 |= (sat_number & 0x7) << 5;
501 pos_b = (sat_number & 0x8) ? 1 : 0;
502
503 /* Fill the LNB number */
504 cmd->data0 |= high_band ? 0 : 4;
505 cmd->data0 |= pol_v ? 8 : 0;
506 cmd->data0 |= pos_b ? 16 : 0;
507
508 return dvb_fe_diseqc_cmd(&parms->p, cmd->len, cmd->msg);
509 }
510
dvbsat_diseqc_set_input(struct dvb_v5_fe_parms_priv * parms,uint16_t t)511 static int dvbsat_diseqc_set_input(struct dvb_v5_fe_parms_priv *parms,
512 uint16_t t)
513 {
514 int rc;
515 enum dvb_sat_polarization pol;
516 int pol_v;
517 int high_band = parms->high_band;
518 int sat_number = parms->p.sat_number;
519 int vol_high = 0;
520 int tone_on = 0;
521 struct diseqc_cmd cmd;
522 const struct dvb_sat_lnb_priv *lnb = (void *)parms->p.lnb;
523
524 if (sat_number < 0 && t) {
525 dvb_logwarn(_("DiSEqC disabled. Can't tune using SCR/Unicable."));
526 return 0;
527 }
528
529 dvb_fe_retrieve_parm(&parms->p, DTV_POLARIZATION, &pol);
530 pol_v = (pol == POLARIZATION_V) || (pol == POLARIZATION_R);
531
532 if (!lnb->freqrange[0].rangeswitch) {
533 /*
534 * Bandstacking switches don't use 2 bands nor use
535 * DISEqC for setting the polarization. It also doesn't
536 * use any tone/tone burst
537 */
538 pol_v = 0;
539 high_band = 1;
540 if (parms->p.current_sys == SYS_ISDBS)
541 vol_high = 1;
542 } else {
543 /* Adjust voltage/tone accordingly */
544 if (sat_number < 2) {
545 vol_high = pol_v ? 0 : 1;
546 tone_on = high_band;
547 }
548 }
549
550 rc = dvb_fe_sec_voltage(&parms->p, 1, vol_high);
551 if (rc)
552 return rc;
553
554 rc = dvb_fe_sec_tone(&parms->p, SEC_TONE_OFF);
555 if (rc)
556 return rc;
557
558 if (sat_number >= 0) {
559 /* DiSEqC is enabled. Send DiSEqC commands */
560 usleep(15 * 1000);
561
562 if (!t)
563 rc = dvbsat_diseqc_write_to_port_group(parms, &cmd, high_band,
564 pol_v, sat_number);
565 else
566 rc = dvbsat_scr_odu_channel_change(parms, &cmd, high_band,
567 pol_v, sat_number, t);
568
569 if (rc) {
570 dvb_logerr(_("sending diseq failed"));
571 return rc;
572 }
573 usleep((15 + parms->p.diseqc_wait) * 1000);
574
575 /* miniDiSEqC/Toneburst commands are defined only for up to 2 sattelites */
576 if (parms->p.sat_number < 2) {
577 rc = dvb_fe_diseqc_burst(&parms->p, parms->p.sat_number);
578 if (rc)
579 return rc;
580 }
581 usleep(15 * 1000);
582 }
583
584 rc = dvb_fe_sec_tone(&parms->p, tone_on ? SEC_TONE_ON : SEC_TONE_OFF);
585
586 return rc;
587 }
588
dvb_sat_real_freq(struct dvb_v5_fe_parms * p,int freq)589 int dvb_sat_real_freq(struct dvb_v5_fe_parms *p, int freq)
590 {
591 struct dvb_v5_fe_parms_priv *parms = (void *)p;
592 const struct dvb_sat_lnb_priv *lnb = (void *)p->lnb;
593 int new_freq, i;
594
595 if (!lnb || !dvb_fe_is_satellite(p->current_sys))
596 return freq;
597
598 new_freq = freq + parms->freq_offset;
599
600 for (i = 0; i < ARRAY_SIZE(lnb->freqrange) && lnb->freqrange[i].low; i++) {
601 if (new_freq / 1000 < lnb->freqrange[i].low || new_freq / 1000 > lnb->freqrange[i].high)
602 continue;
603 return new_freq;
604 }
605
606 /* Weird: frequency is out of LNBf range */
607 dvb_logerr(_("frequency %.2fMHz (tune freq %.2fMHz) is out of LNBf %s range"),
608 new_freq/ 1000., freq / 1000., lnb->desc.name);
609 return 0;
610 }
611
612
613 /*
614 * DVB satellite get/set params hooks
615 */
616
617
dvb_sat_get_freq(struct dvb_v5_fe_parms * p,uint16_t * t)618 static int dvb_sat_get_freq(struct dvb_v5_fe_parms *p, uint16_t *t)
619 {
620 struct dvb_v5_fe_parms_priv *parms = (void *)p;
621 const struct dvb_sat_lnb_priv *lnb = (void *)p->lnb;
622 enum dvb_sat_polarization pol;
623 uint32_t freq;
624 int j;
625
626 if (!lnb) {
627 dvb_logerr(_("Need a LNBf to work"));
628 return 0;
629 }
630
631 parms->high_band = 0;
632 parms->freq_offset = 0;
633
634 dvb_fe_retrieve_parm(&parms->p, DTV_FREQUENCY, &freq);
635
636 if (!lnb->freqrange[1].low) {
637 if (parms->p.verbose)
638 dvb_log("LNBf with a single LO at %.2f MHz", parms->freq_offset/1000.);
639
640 /* Trivial case: LNBf with a single local oscilator(LO) */
641 parms->freq_offset = lnb->freqrange[0].int_freq * 1000;
642 return freq;
643 }
644
645 if (lnb->freqrange[0].pol) {
646 if (parms->p.verbose > 1)
647 dvb_log("LNBf polarity driven");
648
649 /* polarization-controlled multi-LO multipoint LNBf (bandstacking) */
650 dvb_fe_retrieve_parm(&parms->p, DTV_POLARIZATION, &pol);
651
652 for (j = 0; j < ARRAY_SIZE(lnb->freqrange) && lnb->freqrange[j].low; j++) {
653 if (freq < lnb->freqrange[j].low * 1000 ||
654 freq > lnb->freqrange[j].high * 1000 ||
655 pol != lnb->freqrange[j].pol)
656 continue;
657
658 parms->freq_offset = lnb->freqrange[j].int_freq * 1000;
659 return freq;
660 }
661 } else {
662 if (parms->p.verbose > 1)
663 dvb_log("Seeking for LO for %.2f MHz frequency", freq / 1000000.);
664 /* Multi-LO (dual-band) LNBf using DiSEqC */
665 for (j = 0; j < ARRAY_SIZE(lnb->freqrange) && lnb->freqrange[j].low; j++) {
666 if (parms->p.verbose > 1)
667 dvb_log("LO setting %i: %.2f MHz to %.2f MHz", j,
668 lnb->freqrange[j].low / 1000., lnb->freqrange[j].high / 1000.);
669
670 if (freq < lnb->freqrange[j].low * 1000 || freq > lnb->freqrange[j].high * 1000)
671 continue;
672 if (lnb->freqrange[j].rangeswitch && freq > lnb->freqrange[j].rangeswitch * 1000) {
673 if (j + 1 < ARRAY_SIZE(lnb->freqrange) && lnb->freqrange[j + 1].low)
674 j++;
675 }
676
677 /* Sets DiSEqC to high_band if not low band */
678 if (j)
679 parms->high_band = 1;
680
681 if (parms->p.freq_bpf) {
682 /* For SCR/Unicable setups */
683 *t = (((freq / 1000) + parms->p.freq_bpf + 2) / 4) - 350;
684 parms->freq_offset += ((*t + 350) * 4) * 1000;
685 if (parms->p.verbose)
686 dvb_log("BPF: %d KHz", parms->p.freq_bpf);
687 } else {
688 parms->freq_offset = lnb->freqrange[j].int_freq * 1000;
689 if (parms->p.verbose > 1)
690 dvb_log("Multi-LO LNBf. using LO setting %i at %.2f MHz", j, parms->freq_offset / 1000.);
691 }
692 return freq;
693 }
694 }
695 dvb_logerr("frequency: %.2f MHz is out of LNBf range\n",
696 freq / 1000.);
697 return 0;
698 }
699
dvb_sat_set_parms(struct dvb_v5_fe_parms * p)700 int dvb_sat_set_parms(struct dvb_v5_fe_parms *p)
701 {
702 struct dvb_v5_fe_parms_priv *parms = (void *)p;
703 uint32_t freq;
704 uint16_t t = 0;
705 int rc;
706
707 freq = dvb_sat_get_freq(p, &t);
708 if (!freq)
709 return -EINVAL;
710
711 if (parms->p.verbose)
712 dvb_log("frequency: %.2f MHz, high_band: %d", freq / 1000., parms->high_band);
713
714 rc = dvbsat_diseqc_set_input(parms, t);
715
716 freq = freq - parms->freq_offset;
717
718 if (parms->p.verbose)
719 dvb_log("L-Band frequency: %.2f MHz (offset = %.2f MHz)", freq / 1000., parms->freq_offset/1000.);
720
721 dvb_fe_store_parm(&parms->p, DTV_FREQUENCY, freq);
722
723 return rc;
724 }
725
726