• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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