1 /*
2  * Copyright (c) 2011-2012 - 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 #include <sys/types.h>
19 
20 #include "dvb-fe-priv.h"
21 #include "dvb-v5.h"
22 #include <libdvbv5/dvb-dev.h>
23 #include <libdvbv5/countries.h>
24 #include <libdvbv5/dvb-v5-std.h>
25 
26 #include <inttypes.h>
27 #include <math.h>
28 #include <stddef.h>
29 #include <time.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 
33 #include <config.h>
34 
35 #ifdef ENABLE_NLS
36 # include <stdio.h>
37 # include <libintl.h>
38 # define _(string) dgettext(LIBDVBV5_DOMAIN, string)
39 # define P_(singular, plural, n) dngettext(LIBDVBV5_DOMAIN, singular, plural, n)
40 
41 static int libdvbv5_initialized = 0;
42 
43 #else
44 # define _(string) string
45 # define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
46 #endif
47 
48 # define N_(string) string
49 
50 #define MAX_TIME		10	/* 1.0 seconds */
51 
52 #define xioctl(fh, request, arg...) ({					\
53 	int __rc;							\
54 	struct timespec __start, __end;					\
55 									\
56 	clock_gettime(CLOCK_MONOTONIC, &__start);			\
57 	do {								\
58 		__rc = ioctl(fh, request, ##arg);			\
59 		if (__rc != -1)						\
60 			break;						\
61 		if ((errno != EINTR) && (errno != EAGAIN))		\
62 			break;						\
63 		clock_gettime(CLOCK_MONOTONIC, &__end);			\
64 		if (__end.tv_sec * 10 + __end.tv_nsec / 100000000 >	\
65 		    __start.tv_sec * 10 + __start.tv_nsec / 100000000 +	\
66 		    MAX_TIME)						\
67 			break;						\
68 	} while (1);							\
69 									\
70 	__rc;								\
71 })
72 
libdvbv5_initialize(void)73 static void libdvbv5_initialize(void)
74 {
75 #ifdef ENABLE_NLS
76 	if (libdvbv5_initialized)
77 		return;
78 	bindtextdomain(LIBDVBV5_DOMAIN, LOCALEDIR);
79 	libdvbv5_initialized = 1;
80 #endif
81 }
82 
dvb_v5_free(struct dvb_v5_fe_parms_priv * parms)83 void dvb_v5_free(struct dvb_v5_fe_parms_priv *parms)
84 {
85 	if (parms->fname)
86 		free(parms->fname);
87 
88 	free(parms);
89 }
90 
dvb_fe_dummy(void)91 struct dvb_v5_fe_parms *dvb_fe_dummy(void)
92 {
93 	struct dvb_v5_fe_parms_priv *parms = NULL;
94 
95 	libdvbv5_initialize();
96 
97 	parms = calloc(sizeof(*parms), 1);
98 	if (!parms)
99 		return NULL;
100 	parms->p.logfunc = dvb_default_log;
101 	parms->fd = -1;
102 	parms->p.default_charset = "iso-8859-1";
103 	parms->p.output_charset = "utf-8";
104 	parms->p.lna = LNA_AUTO;
105 	parms->p.sat_number = -1;
106 	parms->p.abort = 0;
107 	parms->country = COUNTRY_UNKNOWN;
108 
109 	return &parms->p;
110 }
111 
dvb_fe_open(int adapter,int frontend,unsigned verbose,unsigned use_legacy_call)112 struct dvb_v5_fe_parms *dvb_fe_open(int adapter, int frontend,
113 						  unsigned verbose,
114 						  unsigned use_legacy_call)
115 {
116 	return dvb_fe_open_flags(adapter, frontend, verbose, use_legacy_call,
117 				 NULL, O_RDWR);
118 
119 }
120 
dvb_fe_open2(int adapter,int frontend,unsigned verbose,unsigned use_legacy_call,dvb_logfunc logfunc)121 struct dvb_v5_fe_parms *dvb_fe_open2(int adapter, int frontend,
122 				    unsigned verbose, unsigned use_legacy_call,
123 				    dvb_logfunc logfunc)
124 {
125 	return dvb_fe_open_flags(adapter, frontend, verbose, use_legacy_call,
126 				 logfunc, O_RDWR);
127 }
128 
dvb_fe_open_flags(int adapter,int frontend,unsigned verbose,unsigned use_legacy_call,dvb_logfunc logfunc,int flags)129 struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
130 					  unsigned verbose,
131 					  unsigned use_legacy_call,
132 					  dvb_logfunc logfunc,
133 					  int flags)
134 {
135 	int ret;
136 	char *fname;
137 	struct dvb_device *dvb;
138 	struct dvb_dev_list *dvb_dev;
139 	struct dvb_v5_fe_parms_priv *parms = NULL;
140 
141 	libdvbv5_initialize();
142 
143 	if (logfunc == NULL)
144 		logfunc = dvb_default_log;
145 
146 	dvb = dvb_dev_alloc();
147 	dvb_dev_find(dvb, NULL, NULL);
148 	dvb_dev = dvb_dev_seek_by_adapter(dvb, adapter, frontend,
149 				     DVB_DEVICE_FRONTEND);
150 	if (!dvb_dev) {
151 		logfunc(LOG_ERR, _("adapter %d, frontend %d not found"),
152 			adapter, frontend);
153 		dvb_dev_free(dvb);
154 		return NULL;
155 	}
156 	fname = strdup(dvb_dev->path);
157 
158 	if (!strcmp(dvb_dev->bus_addr, "platform:dvbloopback")) {
159 		logfunc(LOG_WARNING, _("Detected dvbloopback"));
160 		flags |= O_NONBLOCK;
161 	}
162 
163 	dvb_dev_free(dvb);
164 	if (!fname) {
165 		logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
166 		return NULL;
167 	}
168 	parms = calloc(sizeof(*parms), 1);
169 	if (!parms) {
170 		logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
171 		free(fname);
172 		return NULL;
173 	}
174 	parms->p.verbose = verbose;
175 	parms->p.default_charset = "iso-8859-1";
176 	parms->p.output_charset = "utf-8";
177 	parms->p.logfunc = logfunc;
178 	parms->p.lna = LNA_AUTO;
179 	parms->p.sat_number = -1;
180 	parms->p.abort = 0;
181 	parms->country = COUNTRY_UNKNOWN;
182 
183 	if (use_legacy_call)
184 		parms->p.legacy_fe = 1;
185 
186 	ret = dvb_fe_open_fname(parms, fname, flags);
187 	if (ret < 0) {
188 		dvb_v5_free(parms);
189 		return NULL;
190 	}
191 
192 	return &parms->p;
193 }
194 
195 static int __dvb_fe_snprintf_eng(char *buf, int len, float val, int metric);
196 
dvb_fe_open_fname(struct dvb_v5_fe_parms_priv * parms,char * fname,int flags)197 int dvb_fe_open_fname(struct dvb_v5_fe_parms_priv *parms, char *fname,
198 		      int flags)
199 {
200 	struct dtv_properties dtv_prop;
201 	int fd, i;
202 
203 	fd = open(fname, flags, 0);
204 	if (fd == -1) {
205 		dvb_logerr(_("%s while opening %s"), strerror(errno), fname);
206 		free(fname);
207 		return -errno;
208 	}
209 
210 	if (xioctl(fd, FE_GET_INFO, &parms->p.info) == -1) {
211 		dvb_perror("FE_GET_INFO");
212 		close(fd);
213 		return -errno;
214 	}
215 
216 	if (parms->p.verbose) {
217 		fe_caps_t caps = parms->p.info.caps;
218 
219 		dvb_log(_("Device %s (%s) capabilities:"),
220 			parms->p.info.name, fname);
221 		for (i = 0; i < ARRAY_SIZE(fe_caps_name); i++) {
222 			if (caps & fe_caps_name[i].idx)
223 				dvb_log ("     %s", fe_caps_name[i].name);
224 		}
225 	}
226 
227 	parms->fname = fname;
228 	parms->fd = fd;
229 	parms->fe_flags = flags;
230 	parms->dvb_prop[0].cmd = DTV_API_VERSION;
231 	parms->dvb_prop[1].cmd = DTV_DELIVERY_SYSTEM;
232 
233 	dtv_prop.num = 2;
234 	dtv_prop.props = parms->dvb_prop;
235 
236 	/* Detect a DVBv3 device */
237 	if (parms->p.legacy_fe || xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
238 		parms->dvb_prop[0].u.data = 0x300;
239 		parms->dvb_prop[1].u.data = SYS_UNDEFINED;
240 	}
241 
242 	parms->p.version = parms->dvb_prop[0].u.data;
243 	parms->p.current_sys = parms->dvb_prop[1].u.data;
244 	if (parms->p.verbose)
245 		dvb_log (_("DVB API Version %d.%d%s, Current v5 delivery system: %s"),
246 			parms->p.version / 256,
247 			parms->p.version % 256,
248 			parms->p.legacy_fe ? _(" (forcing DVBv3 calls)") : "",
249 			delivery_system_name[parms->p.current_sys]);
250 
251 	if (parms->p.version < 0x500)
252 		parms->p.legacy_fe = 1;
253 
254 	if (parms->p.version >= 0x50a)
255 		parms->p.has_v5_stats = 1;
256 	else
257 		parms->p.has_v5_stats = 0;
258 
259 	if (parms->p.legacy_fe || parms->p.version < 0x505) {
260 		parms->p.legacy_fe = 1;
261 		switch(parms->p.info.type) {
262 		case FE_QPSK:
263 			parms->p.current_sys = SYS_DVBS;
264 			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
265 			if (parms->p.version < 0x0500)
266 				break;
267 			if (parms->p.info.caps & FE_CAN_2G_MODULATION)
268 				parms->p.systems[parms->p.num_systems++] = SYS_DVBS2;
269 			if (parms->p.info.caps & FE_CAN_TURBO_FEC)
270 				parms->p.systems[parms->p.num_systems++] = SYS_TURBO;
271 			break;
272 		case FE_QAM:
273 			parms->p.current_sys = SYS_DVBC_ANNEX_A;
274 			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
275 			break;
276 		case FE_OFDM:
277 			parms->p.current_sys = SYS_DVBT;
278 			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
279 			if (parms->p.version < 0x0500)
280 				break;
281 			if (parms->p.info.caps & FE_CAN_2G_MODULATION)
282 				parms->p.systems[parms->p.num_systems++] = SYS_DVBT2;
283 			break;
284 		case FE_ATSC:
285 			if (parms->p.info.caps & (FE_CAN_8VSB | FE_CAN_16VSB))
286 				parms->p.systems[parms->p.num_systems++] = SYS_ATSC;
287 			if (parms->p.info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO))
288 				parms->p.systems[parms->p.num_systems++] = SYS_DVBC_ANNEX_B;
289 			parms->p.current_sys = parms->p.systems[0];
290 			break;
291 		}
292 		if (!parms->p.num_systems) {
293 			dvb_logerr(_("delivery system not detected"));
294 			close(fd);
295 			return -EINVAL;
296 		}
297 	} else {
298 		parms->dvb_prop[0].cmd = DTV_ENUM_DELSYS;
299 		parms->n_props = 1;
300 		dtv_prop.num = 1;
301 		dtv_prop.props = parms->dvb_prop;
302 		if (xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
303 			dvb_perror("FE_GET_PROPERTY");
304 			close(fd);
305 			return -errno;
306 		}
307 		parms->p.num_systems = parms->dvb_prop[0].u.buffer.len;
308 		for (i = 0; i < parms->p.num_systems; i++)
309 			parms->p.systems[i] = parms->dvb_prop[0].u.buffer.data[i];
310 
311 		if (parms->p.num_systems == 0) {
312 			dvb_logerr(_("driver returned 0 supported delivery systems!"));
313 			close(fd);
314 			return -EINVAL;
315 		}
316 	}
317 
318 	if (parms->p.verbose) {
319 		dvb_log(P_("Supported delivery system: ", "Supported delivery systems: ", parms->p.num_systems));
320 		for (i = 0; i < parms->p.num_systems; i++) {
321 			if (parms->p.systems[i] == parms->p.current_sys)
322 				dvb_log ("    [%s]",
323 					delivery_system_name[parms->p.systems[i]]);
324 			else
325 				dvb_log ("     %s",
326 					delivery_system_name[parms->p.systems[i]]);
327 		}
328 		if (parms->p.legacy_fe || parms->p.version < 0x505)
329 			dvb_log(_("Warning: new delivery systems like ISDB-T, ISDB-S, DMB-TH, DSS, ATSC-MH will be miss-detected by a DVBv5.4 or earlier API call"));
330 	}
331 
332 	/*
333 	 * Fix a bug at some DVB drivers
334 	 */
335 	if (parms->p.current_sys == SYS_UNDEFINED)
336 		parms->p.current_sys = parms->p.systems[0];
337 
338 	/* Prepare to use the delivery system */
339 	parms->n_props = dvb_add_parms_for_sys(&parms->p, parms->p.current_sys);
340 
341 	if ((flags & O_ACCMODE) == O_RDWR)
342 		dvb_set_sys(&parms->p, parms->p.current_sys);
343 
344 	if (parms->p.verbose) {
345 		char buf[256];
346 		uint32_t frq_min, frq_max, frq_stp, frq_tol;
347 
348 		frq_min = parms->p.info.frequency_min;
349 		frq_max = parms->p.info.frequency_max;
350 		frq_stp = parms->p.info.frequency_stepsize;
351 		frq_tol = parms->p.info.frequency_tolerance;
352 		if (parms->p.info.type == FE_QPSK) {
353 			/* For Satellite, frequencies are in kHz */
354 			frq_min *= 1000;
355 			frq_max *= 1000;
356 			frq_stp *= 1000;
357 			frq_tol *= 1000;
358 		}
359 
360 		dvb_log(_("Frequency range for the current standard: "));
361 
362 		__dvb_fe_snprintf_eng(buf, sizeof(buf), frq_min, 1);
363 		dvb_log(_("From:       %11sHz"), buf);
364 		__dvb_fe_snprintf_eng(buf, sizeof(buf), frq_max, 1);
365 		dvb_log(_("To:         %11sHz"), buf);
366 		if (frq_stp) {
367 			__dvb_fe_snprintf_eng(buf, sizeof(buf), frq_stp, 1);
368 			dvb_log(_("Step:       %11sHz"), buf);
369 		}
370 		if (frq_tol) {
371 			__dvb_fe_snprintf_eng(buf, sizeof(buf), frq_tol, 1);
372 			dvb_log(_("Tolerance:  %11sHz"), buf);
373 		}
374 
375 		if (parms->p.info.type == FE_QPSK || parms->p.info.type == FE_QAM) {
376 			dvb_log(_("Symbol rate ranges for the current standard: "));
377 			__dvb_fe_snprintf_eng(buf, sizeof(buf), parms->p.info.symbol_rate_min, 1);
378 			dvb_log(_("From:       %11sBauds"), buf);
379 			__dvb_fe_snprintf_eng(buf, sizeof(buf), parms->p.info.symbol_rate_max, 1);
380 			dvb_log(_("To:         %11sBauds"), buf);
381 			if (parms->p.info.symbol_rate_tolerance) {
382 				__dvb_fe_snprintf_eng(buf, sizeof(buf), parms->p.info.symbol_rate_tolerance, 1);
383 				dvb_log(_("Tolerance:  %11sBauds"), buf);
384 			}
385 		}
386 	}
387 
388 	/*
389 	 * Prepare the status struct - DVBv5.10 parameters should
390 	 * come first, as they'll be read together.
391 	 */
392 	parms->stats.prop[0].cmd = DTV_STAT_SIGNAL_STRENGTH;
393 	parms->stats.prop[1].cmd = DTV_STAT_CNR;
394 	parms->stats.prop[2].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
395 	parms->stats.prop[3].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT;
396 	parms->stats.prop[4].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
397 	parms->stats.prop[5].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
398 	parms->stats.prop[6].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
399 	parms->stats.prop[7].cmd = DTV_STAT_TOTAL_BLOCK_COUNT;
400 
401 	/* Now, status and the calculated stats */
402 	parms->stats.prop[8].cmd = DTV_STATUS;
403 	parms->stats.prop[9].cmd = DTV_BER;
404 	parms->stats.prop[10].cmd = DTV_PER;
405 	parms->stats.prop[11].cmd = DTV_QUALITY;
406 	parms->stats.prop[12].cmd = DTV_PRE_BER;
407 
408 	return 0;
409 }
410 
411 
dvb_fe_is_satellite(uint32_t delivery_system)412 int dvb_fe_is_satellite(uint32_t delivery_system)
413 {
414 	switch (delivery_system) {
415 	case SYS_DVBS:
416 	case SYS_DVBS2:
417 	case SYS_TURBO:
418 	case SYS_ISDBS:
419 		return 1;
420 	default:
421 		return 0;
422 
423 	}
424 }
425 
__dvb_fe_close(struct dvb_v5_fe_parms_priv * parms)426 void __dvb_fe_close(struct dvb_v5_fe_parms_priv *parms)
427 {
428 	if (!parms || parms->fd < 0)
429 		return;
430 
431 	/* Disable LNBf power */
432 	if (dvb_fe_is_satellite(parms->p.current_sys))
433 		dvb_fe_sec_voltage(&parms->p, 0, 0);
434 
435 	close(parms->fd);
436 	parms->fd = -1;
437 }
438 
dvb_fe_close(struct dvb_v5_fe_parms * p)439 void dvb_fe_close(struct dvb_v5_fe_parms *p)
440 {
441 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
442 
443 	if (!parms)
444 		return;
445 
446 	if (parms->fd < 0) {
447 		dvb_v5_free(parms);
448 		return;
449 	}
450 
451 	/* Disable LNBf power */
452 	if (dvb_fe_is_satellite(parms->p.current_sys))
453 		dvb_fe_sec_voltage(&parms->p, 0, 0);
454 
455 	close(parms->fd);
456 
457 	dvb_v5_free(parms);
458 }
459 
460 
dvb_add_parms_for_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)461 int dvb_add_parms_for_sys(struct dvb_v5_fe_parms *p,
462 			  fe_delivery_system_t sys)
463 {
464 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
465 	struct dtv_property *dvb_prop = parms->dvb_prop;
466 	unsigned max_size = ARRAY_SIZE(parms->dvb_prop);
467 	const unsigned int *sys_props;
468 	int n;
469 
470 	/* Make dvb properties reflect the current standard */
471 
472 	sys_props = dvb_v5_delivery_system[sys];
473 	if (!sys_props)
474 		return -EINVAL;
475 
476 	n = 0;
477 	while (sys_props[n] && n < max_size - 1) {
478 		dvb_prop[n].cmd = sys_props[n];
479 		dvb_prop[n].u.data = 0;
480 		n++;
481 	}
482 	dvb_prop[n].cmd = DTV_DELIVERY_SYSTEM;
483 	dvb_prop[n].u.data = sys;
484 	n++;
485 
486 	return n;
487 }
488 
__dvb_set_sys(struct dvb_v5_fe_parms * p,fe_delivery_system_t sys)489 int __dvb_set_sys(struct dvb_v5_fe_parms *p, fe_delivery_system_t sys)
490 {
491 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
492 	struct dtv_property dvb_prop[1];
493 	struct dtv_properties prop;
494 	struct dvb_frontend_info new_info;
495 	int rc;
496 
497 	if (sys != parms->p.current_sys) {
498 		/* Disable LNBf power */
499 		if (dvb_fe_is_satellite(parms->p.current_sys) &&
500 		    !dvb_fe_is_satellite(sys))
501 			dvb_fe_sec_voltage(&parms->p, 0, 0);
502 
503 		/* Can't change standard with the legacy FE support */
504 		if (parms->p.legacy_fe)
505 			return -EINVAL;
506 
507 		dvb_prop[0].cmd = DTV_DELIVERY_SYSTEM;
508 		dvb_prop[0].u.data = sys;
509 		prop.num = 1;
510 		prop.props = dvb_prop;
511 
512 		if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) {
513 			dvb_perror(_("Set delivery system"));
514 			return -errno;
515 		}
516 	}
517 
518 	/*
519 	 * This should not happen frequently, as this ioctl is pretty
520 	 * straight forward. However, if it happens, it is better
521 	 * to print an error message and ignore the error, as it
522 	 * may still work.
523 	 */
524 	if (xioctl(parms->fd, FE_GET_INFO, &new_info) == -1)
525 		dvb_perror(_("Can't retrieve DVB information for the new delivery system."));
526 	else
527 		parms->p.info = new_info;
528 
529 	rc = dvb_add_parms_for_sys(&parms->p, sys);
530 	if (rc < 0)
531 		return -EINVAL;
532 
533 	parms->p.current_sys = sys;
534 	parms->n_props = rc;
535 
536 	return 0;
537 }
538 
dvbv3_type(uint32_t delivery_system)539 static enum dvbv3_emulation_type dvbv3_type(uint32_t delivery_system)
540 {
541 	switch (delivery_system) {
542 	case SYS_DVBC_ANNEX_A:
543 	case SYS_DVBC_ANNEX_C:
544 		return DVBV3_QAM;
545 	case SYS_DVBS:
546 	case SYS_DVBS2:
547 	case SYS_TURBO:
548 	case SYS_ISDBS:
549 	case SYS_DSS:
550 		return DVBV3_QPSK;
551 	case SYS_DVBT:
552 	case SYS_DVBT2:
553 	case SYS_ISDBT:
554 	case SYS_DTMB:
555 		return DVBV3_OFDM;
556 	case SYS_ATSC:
557 	case SYS_ATSCMH:
558 	case SYS_DVBC_ANNEX_B:
559 		return DVBV3_ATSC;
560 	default:
561 		return DVBV3_UNKNOWN;
562 	}
563 };
564 
is_dvbv3_delsys(uint32_t delsys)565 static int is_dvbv3_delsys(uint32_t delsys)
566 {
567 	int status;
568 
569 	status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
570 		 (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
571 
572 	return status;
573 }
574 
dvb_set_compat_delivery_system(struct dvb_v5_fe_parms * p,uint32_t desired_system)575 int dvb_set_compat_delivery_system(struct dvb_v5_fe_parms *p,
576 				   uint32_t desired_system)
577 {
578 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
579 	int i;
580 	uint32_t delsys = SYS_UNDEFINED;
581 	enum dvbv3_emulation_type type;
582 
583 	/* Check if the desired delivery system is supported */
584 	for (i = 0; i < parms->p.num_systems; i++) {
585 		if (parms->p.systems[i] == desired_system) {
586 			dvb_set_sys(&parms->p, desired_system);
587 			return 0;
588 		}
589 	}
590 
591 	/*
592 	 * Find the closest DVBv3 system that matches the delivery
593 	 * system.
594 	 */
595 	type = dvbv3_type(desired_system);
596 
597 	/*
598 	 * Get the last non-DVBv3 delivery system that has the same type
599 	 * of the desired system
600 	 */
601 	for (i = 0; i < parms->p.num_systems; i++) {
602 		if ((dvbv3_type(parms->p.systems[i]) == type) &&
603 		    !is_dvbv3_delsys(parms->p.systems[i]))
604 			delsys = parms->p.systems[i];
605 	}
606 
607 	if (delsys == SYS_UNDEFINED)
608 		return -EINVAL;
609 
610 	dvb_log(_("Using a DVBv3 compat file for %s"), delivery_system_name[delsys]);
611 
612 	dvb_set_sys(&parms->p, delsys);
613 
614 	/* Put ISDB-T into auto mode */
615 	if (delsys == SYS_ISDBT) {
616 		dvb_fe_store_parm(&parms->p, DTV_BANDWIDTH_HZ, 6000000);
617 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_PARTIAL_RECEPTION, 0);
618 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SOUND_BROADCASTING, 0);
619 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SUBCHANNEL_ID, 0);
620 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SEGMENT_IDX, 0);
621 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_SB_SEGMENT_COUNT, 0);
622 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYER_ENABLED, 7);
623 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_FEC, FEC_AUTO);
624 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_FEC, FEC_AUTO);
625 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_FEC, FEC_AUTO);
626 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_MODULATION, QAM_AUTO);
627 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_MODULATION, QAM_AUTO);
628 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_MODULATION, QAM_AUTO);
629 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0);
630 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0);
631 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0);
632 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0);
633 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0);
634 		dvb_fe_store_parm(&parms->p, DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0);
635 	}
636 	return 0;
637 }
638 
dvb_cmd_name(int cmd)639 const char *dvb_cmd_name(int cmd)
640 {
641 	if (cmd >= 0 && cmd < ARRAY_SIZE(dvb_v5_name))
642 		return dvb_v5_name[cmd];
643 	if (cmd >= DTV_USER_COMMAND_START && cmd <= DTV_MAX_USER_COMMAND)
644 		return dvb_user_name[cmd - DTV_USER_COMMAND_START];
645 	if (cmd >= DTV_STAT_COMMAND_START && cmd <= DTV_MAX_STAT_COMMAND)
646 		return dvb_stat_name[cmd - DTV_STAT_COMMAND_START];
647 	return NULL;
648 }
649 
dvb_attr_names(int cmd)650 const char *const *dvb_attr_names(int cmd)
651 {
652 	if (cmd >= 0 && cmd < DTV_MAX_COMMAND)
653 		return dvb_v5_attr_names[cmd];
654 
655 	if (cmd >= DTV_USER_COMMAND_START && cmd <= DTV_MAX_USER_COMMAND)
656 		return dvb_user_attr_names[cmd - DTV_USER_COMMAND_START];
657 	return NULL;
658 }
659 
dvb_fe_prt_parms(const struct dvb_v5_fe_parms * p)660 void dvb_fe_prt_parms(const struct dvb_v5_fe_parms *p)
661 {
662 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
663 	int i;
664 
665 	for (i = 0; i < parms->n_props; i++) {
666 		const char * const *attr_name = dvb_attr_names(parms->dvb_prop[i].cmd);
667 		if (attr_name) {
668 			int j;
669 
670 			for (j = 0; j < parms->dvb_prop[i].u.data; j++) {
671 				if (!*attr_name)
672 					break;
673 				attr_name++;
674 			}
675 		}
676 
677 		if (!attr_name || !*attr_name)
678 			dvb_log("%s = %u",
679 				dvb_cmd_name(parms->dvb_prop[i].cmd),
680 				parms->dvb_prop[i].u.data);
681 		else
682 			dvb_log("%s = %s",
683 				dvb_cmd_name(parms->dvb_prop[i].cmd),
684 				*attr_name);
685 	}
686 };
687 
dvb_fe_retrieve_parm(const struct dvb_v5_fe_parms * p,unsigned cmd,uint32_t * value)688 int dvb_fe_retrieve_parm(const struct dvb_v5_fe_parms *p,
689 				unsigned cmd, uint32_t *value)
690 {
691 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
692 	int i;
693 	for (i = 0; i < parms->n_props; i++) {
694 		if (parms->dvb_prop[i].cmd != cmd)
695 			continue;
696 		*value = parms->dvb_prop[i].u.data;
697 		return 0;
698 	}
699 	dvb_logerr(_("command %s (%d) not found during retrieve"),
700 		dvb_cmd_name(cmd), cmd);
701 
702 	return -EINVAL;
703 }
704 
dvb_fe_store_parm(struct dvb_v5_fe_parms * p,unsigned cmd,uint32_t value)705 int dvb_fe_store_parm(struct dvb_v5_fe_parms *p,
706 			     unsigned cmd, uint32_t value)
707 {
708 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
709 	int i;
710 	for (i = 0; i < parms->n_props; i++) {
711 		if (parms->dvb_prop[i].cmd != cmd)
712 			continue;
713 		parms->dvb_prop[i].u.data = value;
714 		return 0;
715 	}
716 	dvb_logerr(_("command %s (%d) not found during store"),
717 		dvb_cmd_name(cmd), cmd);
718 
719 	return -EINVAL;
720 }
721 
dvb_copy_fe_props(const struct dtv_property * from,int n,struct dtv_property * to)722 static int dvb_copy_fe_props(const struct dtv_property *from, int n, struct dtv_property *to)
723 {
724 	int i, j;
725 	for (i = 0, j = 0; i < n; i++)
726 		if (from[i].cmd < DTV_USER_COMMAND_START)
727 			to[j++] = from[i];
728 	return j;
729 }
730 
__dvb_fe_get_parms(struct dvb_v5_fe_parms * p)731 int __dvb_fe_get_parms(struct dvb_v5_fe_parms *p)
732 {
733 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
734 	int i, n = 0;
735 	const unsigned int *sys_props;
736 	struct dtv_properties prop;
737 	struct dvb_frontend_parameters v3_parms;
738 	uint32_t bw;
739 
740 	sys_props = dvb_v5_delivery_system[parms->p.current_sys];
741 	if (!sys_props)
742 		return -EINVAL;
743 
744 	while (sys_props[n]) {
745 		parms->dvb_prop[n].cmd = sys_props[n];
746 		n++;
747 	}
748 	parms->dvb_prop[n].cmd = DTV_DELIVERY_SYSTEM;
749 	parms->dvb_prop[n].u.data = parms->p.current_sys;
750 	n++;
751 
752 	/* Keep it ready for set */
753 	parms->dvb_prop[n].cmd = DTV_TUNE;
754 	parms->n_props = n;
755 
756 	struct dtv_property fe_prop[DTV_MAX_COMMAND];
757 	n = dvb_copy_fe_props(parms->dvb_prop, n, fe_prop);
758 
759 	prop.props = fe_prop;
760 	prop.num = n;
761 	if (!parms->p.legacy_fe) {
762 		if (xioctl(parms->fd, FE_GET_PROPERTY, &prop) == -1) {
763 			dvb_perror("FE_GET_PROPERTY");
764 			return -errno;
765 		}
766 
767 		/* copy back params from temporary fe_prop */
768 		for (i = 0; i < n; i++) {
769 			if (fe_prop[i].cmd == DTV_FREQUENCY) {
770 				fe_prop[i].u.data = dvb_sat_real_freq(p, fe_prop[i].u.data);
771 				if (!fe_prop[i].u.data)
772 					return -EINVAL;
773 			}
774 			dvb_fe_store_parm(&parms->p, fe_prop[i].cmd, fe_prop[i].u.data);
775 		}
776 
777 		if (parms->p.verbose) {
778 			dvb_log(_("Got parameters for %s:"),
779 			       delivery_system_name[parms->p.current_sys]);
780 			dvb_fe_prt_parms(&parms->p);
781 		}
782 		return 0;
783 	}
784 	/* DVBv3 call */
785 	if (xioctl(parms->fd, FE_GET_FRONTEND, &v3_parms) == -1) {
786 		dvb_perror("FE_GET_FRONTEND");
787 		return -EINVAL;
788 	}
789 
790 	dvb_fe_store_parm(&parms->p, DTV_FREQUENCY, v3_parms.frequency);
791 	dvb_fe_store_parm(&parms->p, DTV_INVERSION, v3_parms.inversion);
792 	switch (parms->p.current_sys) {
793 	case SYS_DVBS:
794 		dvb_fe_store_parm(&parms->p, DTV_SYMBOL_RATE, v3_parms.u.qpsk.symbol_rate);
795 		dvb_fe_store_parm(&parms->p, DTV_INNER_FEC, v3_parms.u.qpsk.fec_inner);
796 		break;
797 	case SYS_DVBC_ANNEX_A:
798 		dvb_fe_store_parm(&parms->p, DTV_SYMBOL_RATE, v3_parms.u.qam.symbol_rate);
799 		dvb_fe_store_parm(&parms->p, DTV_INNER_FEC, v3_parms.u.qam.fec_inner);
800 		dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.qam.modulation);
801 		break;
802 	case SYS_ATSC:
803 	case SYS_ATSCMH:
804 	case SYS_DVBC_ANNEX_B:
805 		dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.vsb.modulation);
806 		break;
807 	case SYS_DVBT:
808 		if (v3_parms.u.ofdm.bandwidth < ARRAY_SIZE(fe_bandwidth_name) -1)
809 			bw = fe_bandwidth_name[v3_parms.u.ofdm.bandwidth];
810 		else bw = 0;
811 		dvb_fe_store_parm(&parms->p, DTV_BANDWIDTH_HZ, bw);
812 		dvb_fe_store_parm(&parms->p, DTV_CODE_RATE_HP, v3_parms.u.ofdm.code_rate_HP);
813 		dvb_fe_store_parm(&parms->p, DTV_CODE_RATE_LP, v3_parms.u.ofdm.code_rate_LP);
814 		dvb_fe_store_parm(&parms->p, DTV_MODULATION, v3_parms.u.ofdm.constellation);
815 		dvb_fe_store_parm(&parms->p, DTV_TRANSMISSION_MODE, v3_parms.u.ofdm.transmission_mode);
816 		dvb_fe_store_parm(&parms->p, DTV_GUARD_INTERVAL, v3_parms.u.ofdm.guard_interval);
817 		dvb_fe_store_parm(&parms->p, DTV_HIERARCHY, v3_parms.u.ofdm.hierarchy_information);
818 		break;
819 	default:
820 		return -EINVAL;
821 	}
822 
823 	return 0;
824 }
825 
826 /* set the delsys default/fixed parameters and replace DVBv5 default values */
dvb_setup_delsys_default(struct dvb_v5_fe_parms * p)827 static void dvb_setup_delsys_default(struct dvb_v5_fe_parms *p)
828 {
829 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
830 	uint32_t cc;
831 
832 	switch (p->current_sys) {
833 	case SYS_ISDBT:
834 		/* Set country code. */
835 		/* if the default country is not known, fallback to BR */
836 		cc = COUNTRY_UNKNOWN;
837 		dvb_fe_retrieve_parm(p, DTV_COUNTRY_CODE, &cc);
838 		if (cc == COUNTRY_UNKNOWN) {
839 			cc = (parms->country == COUNTRY_UNKNOWN)
840 				? BR : parms->country;
841 			dvb_fe_store_parm(p, DTV_COUNTRY_CODE, cc);
842 		}
843 		switch (cc) {
844 		case JP:
845 			p->default_charset = "arib-std-b24";
846 			dvb_fe_store_parm(p, DTV_BANDWIDTH_HZ, 6000000);
847 			break;
848 		/* Americas (SBTVD) */
849 		case AR:
850 		case BO:
851 		case BR:
852 		case CL:
853 		case CR:
854 		case EC:
855 		case GT:
856 		case HN:
857 		case NI:
858 		case PE:
859 		case PY:
860 		case UY:
861 		case VE:
862 			p->default_charset = "iso8859-15";
863 			break;
864 		}
865 		break;
866 	case SYS_ISDBS:
867 		p->default_charset = "arib-std-b24";
868 		if (!p->lnb)
869 			p->lnb = dvb_sat_get_lnb(dvb_sat_search_lnb("110BS"));
870 		break;
871 	default:
872 		break;
873 	}
874 }
875 
__dvb_fe_set_parms(struct dvb_v5_fe_parms * p)876 int __dvb_fe_set_parms(struct dvb_v5_fe_parms *p)
877 {
878 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
879 	/* Use a temporary copy of the parameters so we can safely perform
880 	 * adjustments for satellite */
881 	struct dvb_v5_fe_parms_priv tmp_parms = *parms;
882 
883 	struct dtv_properties prop;
884 	struct dvb_frontend_parameters v3_parms;
885 	uint32_t bw;
886 
887 	if (parms->p.lna != LNA_AUTO && !parms->p.legacy_fe) {
888 		struct dvb_v5_fe_parms_priv tmp_lna_parms;
889 
890 		memset(&prop, 0, sizeof(prop));
891 		prop.props = tmp_lna_parms.dvb_prop;
892 
893 		prop.props[0].cmd = DTV_LNA;
894 		prop.props[0].u.data = parms->p.lna;
895 		prop.num = 1;
896 		if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) {
897 			dvb_perror(_("Setting LNA"));
898 			parms->p.lna = LNA_AUTO;
899 		} else if (parms->p.lna != LNA_AUTO && parms->p.verbose)
900 			dvb_logdbg(_("LNA is %s"), parms->p.lna ? _("ON") : _("OFF"));
901 	}
902 
903 	if (dvb_fe_is_satellite(tmp_parms.p.current_sys)) {
904 		dvb_sat_set_parms(&tmp_parms.p);
905 		/*
906 		 * even though the frequncy prop is kept un-modified here,
907 		 * a later call to dvb_fe_get_parms() issues FE_GET_PROPERTY
908 		 * ioctl and overwrites it with the offset-ed value from
909 		 * the FE. So we need to save the offset here and
910 		 * re-add it in dvb_fe_get_parms().
911 		 * note that dvbv5-{scan,zap} utilities call dvb_fe_get_parms()
912 		 * indirectly from check_frontend() via dvb_fe_get_stats().
913 		 */
914 		parms->freq_offset = tmp_parms.freq_offset;
915 	}
916 
917 	dvb_setup_delsys_default(p);
918 
919 	/* Filter out any user DTV_foo property such as DTV_POLARIZATION */
920 	tmp_parms.n_props = dvb_copy_fe_props(tmp_parms.dvb_prop,
921 					      tmp_parms.n_props,
922 					      tmp_parms.dvb_prop);
923 
924 	memset(&prop, 0, sizeof(prop));
925 	prop.props = tmp_parms.dvb_prop;
926 	prop.num = tmp_parms.n_props;
927 	prop.props[prop.num].cmd = DTV_TUNE;
928 	prop.num++;
929 
930 	if (!parms->p.legacy_fe) {
931 		if (xioctl(parms->fd, FE_SET_PROPERTY, &prop) == -1) {
932 			dvb_perror("FE_SET_PROPERTY");
933 			if (parms->p.verbose)
934 				dvb_fe_prt_parms(&parms->p);
935 			return -errno;
936 		}
937 		return 0;
938 	}
939 	/* DVBv3 call */
940 	dvb_fe_retrieve_parm(&tmp_parms.p, DTV_FREQUENCY, &v3_parms.frequency);
941 	dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INVERSION, &v3_parms.inversion);
942 	switch (tmp_parms.p.current_sys) {
943 	case SYS_DVBS:
944 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_SYMBOL_RATE, &v3_parms.u.qpsk.symbol_rate);
945 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INNER_FEC, &v3_parms.u.qpsk.fec_inner);
946 		break;
947 	case SYS_DVBC_ANNEX_AC:
948 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_SYMBOL_RATE, &v3_parms.u.qam.symbol_rate);
949 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_INNER_FEC, &v3_parms.u.qam.fec_inner);
950 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.qam.modulation);
951 		break;
952 	case SYS_ATSC:
953 	case SYS_ATSCMH:
954 	case SYS_DVBC_ANNEX_B:
955 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.vsb.modulation);
956 		break;
957 	case SYS_DVBT:
958 		for (bw = 0; fe_bandwidth_name[bw] != 0; bw++) {
959 			if (fe_bandwidth_name[bw] == v3_parms.u.ofdm.bandwidth)
960 				break;
961 		}
962 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_BANDWIDTH_HZ, &bw);
963 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_CODE_RATE_HP, &v3_parms.u.ofdm.code_rate_HP);
964 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_CODE_RATE_LP, &v3_parms.u.ofdm.code_rate_LP);
965 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_MODULATION, &v3_parms.u.ofdm.constellation);
966 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_TRANSMISSION_MODE, &v3_parms.u.ofdm.transmission_mode);
967 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_GUARD_INTERVAL, &v3_parms.u.ofdm.guard_interval);
968 		dvb_fe_retrieve_parm(&tmp_parms.p, DTV_HIERARCHY, &v3_parms.u.ofdm.hierarchy_information);
969 		break;
970 	default:
971 		return -EINVAL;
972 	}
973 	if (xioctl(tmp_parms.fd, FE_SET_FRONTEND, &v3_parms) == -1) {
974 		dvb_perror("FE_SET_FRONTEND");
975 		if (tmp_parms.p.verbose)
976 			dvb_fe_prt_parms(&tmp_parms.p);
977 		return -errno;
978 	}
979 
980 	return 0;
981 }
982 
dvb_fe_store_stats(struct dvb_v5_fe_parms_priv * parms,unsigned cmd,enum fecap_scale_params scale,unsigned layer,uint32_t value)983 static struct dtv_stats *dvb_fe_store_stats(struct dvb_v5_fe_parms_priv *parms,
984 			      unsigned cmd,
985 			      enum fecap_scale_params scale,
986 			      unsigned layer,
987 			      uint32_t value)
988 {
989 	int i;
990 
991 	for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
992 		if (parms->stats.prop[i].cmd != cmd)
993 			continue;
994 		parms->stats.prop[i].u.st.stat[layer].scale = scale;
995 		parms->stats.prop[i].u.st.stat[layer].uvalue = value;
996 		if (parms->stats.prop[i].u.st.len < layer + 1)
997 			parms->stats.prop[i].u.st.len = layer + 1;
998 		return &parms->stats.prop[i].u.st.stat[layer];
999 	}
1000 	dvb_logerr(_("%s not found on store"), dvb_cmd_name(cmd));
1001 
1002 	return NULL;
1003 }
1004 
calculate_postBER(struct dvb_v5_fe_parms_priv * parms,unsigned layer)1005 static float calculate_postBER(struct dvb_v5_fe_parms_priv *parms, unsigned layer)
1006 {
1007 	uint64_t n, d;
1008 
1009 	if (!parms->stats.has_post_ber[layer])
1010 		return -EINVAL;
1011 
1012 	d = parms->stats.cur[layer].post_bit_count - parms->stats.prev[layer].post_bit_count;
1013 	if (!d)
1014 		return -EINVAL;
1015 
1016 	n = parms->stats.cur[layer].post_bit_error - parms->stats.prev[layer].post_bit_error;
1017 
1018 	return ((float)n)/d;
1019 }
1020 
calculate_preBER(struct dvb_v5_fe_parms_priv * parms,unsigned layer)1021 static float calculate_preBER(struct dvb_v5_fe_parms_priv *parms, unsigned layer)
1022 {
1023 	uint64_t n, d;
1024 
1025 	if (!parms->stats.has_pre_ber[layer])
1026 		return -EINVAL;
1027 
1028 	d = parms->stats.cur[layer].pre_bit_count - parms->stats.prev[layer].pre_bit_count;
1029 	if (!d)
1030 		return -EINVAL;
1031 
1032 	n = parms->stats.cur[layer].pre_bit_error - parms->stats.prev[layer].pre_bit_error;
1033 
1034 	return ((float)n)/d;
1035 }
1036 
dvb_fe_retrieve_v5_BER(struct dvb_v5_fe_parms_priv * parms,unsigned layer)1037 static struct dtv_stats *dvb_fe_retrieve_v5_BER(struct dvb_v5_fe_parms_priv *parms,
1038 					        unsigned layer)
1039 {
1040 	float ber;
1041 	uint64_t ber64;
1042 
1043 	ber = calculate_postBER(parms, layer);
1044 	if (ber < 0)
1045 		return NULL;
1046 
1047 	/*
1048 	 * Put BER into some DVBv3 compat scale. The thing is that DVBv3 has no
1049 	 * defined scale for BER. So, let's use 10^-7.
1050 	 */
1051 
1052 	ber64 = 10000000 * ber;
1053 	return dvb_fe_store_stats(parms, DTV_BER, FE_SCALE_COUNTER, layer, ber64);
1054 }
1055 
dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms * p,unsigned cmd,unsigned layer)1056 struct dtv_stats *dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms *p,
1057 					      unsigned cmd, unsigned layer)
1058 {
1059 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1060 	int i;
1061 
1062 	if (cmd == DTV_BER && parms->p.has_v5_stats)
1063 		return dvb_fe_retrieve_v5_BER(parms, layer);
1064 
1065 	for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
1066 		if (parms->stats.prop[i].cmd != cmd)
1067 			continue;
1068 		if (layer >= parms->stats.prop[i].u.st.len)
1069 			return NULL;
1070 		return &parms->stats.prop[i].u.st.stat[layer];
1071 	}
1072 	dvb_logerr(_("%s not found on retrieve"), dvb_cmd_name(cmd));
1073 
1074 	return NULL;
1075 }
1076 
dvb_fe_retrieve_stats(struct dvb_v5_fe_parms * p,unsigned cmd,uint32_t * value)1077 int dvb_fe_retrieve_stats(struct dvb_v5_fe_parms *p,
1078 			  unsigned cmd, uint32_t *value)
1079 {
1080 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1081 	struct dtv_stats *stat;
1082 	enum fecap_scale_params scale;
1083 
1084 	stat = dvb_fe_retrieve_stats_layer(&parms->p, cmd, 0);
1085 	if (!stat) {
1086 		if (parms->p.verbose)
1087 			dvb_logdbg(_("%s not found on retrieve"), dvb_cmd_name(cmd));
1088 		return -EINVAL;
1089 	}
1090 
1091 	scale = stat->scale;
1092 	if (scale == FE_SCALE_NOT_AVAILABLE) {
1093 		if (parms->p.verbose)
1094 			dvb_logdbg(_("%s not available"), dvb_cmd_name(cmd));
1095 		return -EINVAL;
1096 	}
1097 
1098 	*value = stat->uvalue;
1099 
1100 	if (parms->p.verbose > 1)
1101 		dvb_logdbg(_("Stats for %s = %d"), dvb_cmd_name(cmd), *value);
1102 
1103 	return 0;
1104 }
1105 
dvb_fe_retrieve_ber(struct dvb_v5_fe_parms * p,unsigned layer,enum fecap_scale_params * scale)1106 float dvb_fe_retrieve_ber(struct dvb_v5_fe_parms *p, unsigned layer,
1107 			  enum fecap_scale_params *scale)
1108 {
1109 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1110 	float ber;
1111 	uint32_t ber32;
1112 
1113 	if (parms->p.has_v5_stats) {
1114 		ber = calculate_postBER(parms, layer);
1115 		if (ber >= 0)
1116 			*scale = FE_SCALE_COUNTER;
1117 		else
1118 			*scale = FE_SCALE_NOT_AVAILABLE;
1119 		return ber;
1120 	}
1121 
1122 	if (layer) {
1123 		*scale = FE_SCALE_NOT_AVAILABLE;
1124 		return -EINVAL;
1125 	}
1126 
1127 	if (dvb_fe_retrieve_stats(&parms->p, DTV_BER, &ber32))
1128 		*scale = FE_SCALE_NOT_AVAILABLE;
1129 	else
1130 		*scale = FE_SCALE_RELATIVE;
1131 
1132 	return ber32;
1133 }
1134 
dvb_fe_retrieve_per(struct dvb_v5_fe_parms * p,unsigned layer)1135 float dvb_fe_retrieve_per(struct dvb_v5_fe_parms *p, unsigned layer)
1136 {
1137 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1138 	uint64_t n, d;
1139 
1140 	if (!parms->stats.has_per[layer]) {
1141 		return -EINVAL;
1142 	}
1143 
1144 	d = parms->stats.cur[layer].block_count - parms->stats.prev[layer].block_count;
1145 	if (!d) {
1146 		return -EINVAL;
1147 	}
1148 
1149 	n = parms->stats.cur[layer].block_error - parms->stats.prev[layer].block_error;
1150 
1151 	return ((float)n)/d;
1152 }
1153 
1154 struct cnr_to_qual_s {
1155 	uint32_t modulation;		/* use QAM_AUTO if it doesn't matter */
1156 	uint32_t fec;			/* Use FEC_NONE if it doesn't matter */
1157 	float cnr_ok, cnr_good;
1158 };
1159 
cnr_arr_to_qual(uint32_t modulation,uint32_t fec,float cnr,struct cnr_to_qual_s * arr,unsigned len)1160 static enum dvb_quality cnr_arr_to_qual(uint32_t modulation,
1161 					 uint32_t fec,
1162 					 float cnr,
1163 					 struct cnr_to_qual_s *arr,
1164 					 unsigned len)
1165 {
1166 	int i;
1167 
1168 	for (i = 0; i < len; i++) {
1169 		if (modulation == arr[i].modulation) {
1170 			if (cnr < arr[i].cnr_ok)
1171 				return DVB_QUAL_POOR;
1172 
1173 			if (cnr < arr[i].cnr_good)
1174 				return DVB_QUAL_OK;
1175 
1176 			return DVB_QUAL_GOOD;
1177 
1178 		}
1179 	}
1180 
1181 	return DVB_QUAL_UNKNOWN;
1182 }
1183 
1184 /* Source: http://www.maxpeak.tv/articles/Maxpeak_Article_2.pdf */
1185 struct cnr_to_qual_s dvb_c_cnr_2_qual[] = {
1186 	{ QAM_256, FEC_NONE,  34., 38.},
1187 	{ QAM_64,  FEC_NONE,  30., 34.},
1188 };
1189 
1190 /*
1191  * Base reference: http://www.maxpeak.tv/articles/Maxpeak_Article_2.pdf
1192  * Used http://www.nws.noaa.gov/noaaport/html/DVB%20S2%20Satellite%20Receiver%20Specs.pdf
1193  * to estimate the missing FEC's
1194  */
1195 struct cnr_to_qual_s dvb_s_cnr_2_qual[] = {
1196 	{ QPSK, FEC_1_2,  7., 10.},
1197 
1198 	{ QPSK, FEC_2_3,  9., 12.},
1199 	{ QPSK, FEC_3_4, 10., 13.},
1200 	{ QPSK, FEC_5_6, 11., 14.},
1201 
1202 	{ QPSK, FEC_7_8, 12., 15.},
1203 };
1204 
1205 struct cnr_to_qual_s dvb_s2_cnr_2_qual[] = {
1206 	{ QPSK,  FEC_1_2,   9.,  12.},
1207 	{ QPSK,  FEC_2_3,  11.,  14.},
1208 	{ QPSK,  FEC_3_4,  12.,  15.},
1209 	{ QPSK,  FEC_5_6,  12.,  15.},
1210 	{ QPSK,  FEC_8_9,  13.,  16.},
1211 	{ QPSK,  FEC_9_10, 13.5, 16.5},
1212 	{ PSK_8, FEC_2_3,  14.5, 17.5},
1213 	{ PSK_8, FEC_3_4,  16.,  19.},
1214 	{ PSK_8, FEC_5_6,  17.5, 20.5},
1215 	{ PSK_8, FEC_8_9,  19.,  22.},
1216 };
1217 
1218 /*
1219  * Minimum values from ARIB STD-B21 for DVB_QUAL_OK.
1220  * As ARIB doesn't define a max value, assume +2dB for DVB_QUAL_GOOD
1221  */
1222 static struct cnr_to_qual_s isdb_t_cnr_2_qual[] = {
1223 	{  DQPSK, FEC_1_2,  6.2,  8.2},
1224 	{  DQPSK, FEC_2_3,  7.7,  9.7},
1225 	{  DQPSK, FEC_3_4,  8.7, 10.7},
1226 	{  DQPSK, FEC_5_6,  9.6, 11.6},
1227 	{  DQPSK, FEC_7_8, 10.4, 12.4},
1228 
1229 	{   QPSK, FEC_1_2,  4.9,  6.9},
1230 	{   QPSK, FEC_2_3,  6.6,  8.6},
1231 	{   QPSK, FEC_3_4,  7.5,  9.5},
1232 	{   QPSK, FEC_5_6,  8.5, 10.5},
1233 	{   QPSK, FEC_7_8,  9.1, 11.5},
1234 
1235 	{ QAM_16, FEC_1_2, 11.5, 13.5},
1236 	{ QAM_16, FEC_2_3, 13.5, 15.5},
1237 	{ QAM_16, FEC_3_4, 14.6, 16.6},
1238 	{ QAM_16, FEC_5_6, 15.6, 17.6},
1239 	{ QAM_16, FEC_7_8, 16.2, 18.2},
1240 
1241 	{ QAM_64, FEC_1_2, 16.5, 18.5},
1242 	{ QAM_64, FEC_2_3, 18.7, 21.7},
1243 	{ QAM_64, FEC_3_4, 20.1, 22.1},
1244 	{ QAM_64, FEC_5_6, 21.3, 23.3},
1245 	{ QAM_64, FEC_7_8, 22.0, 24.0},
1246 };
1247 
1248 /*
1249  * Values obtained from table A.1 of ETSI EN 300 744 v1.6.1
1250  * OK corresponds to Ricean fading; Good to Rayleigh fading
1251  */
1252 static struct cnr_to_qual_s dvb_t_cnr_2_qual[] = {
1253 	{   QPSK, FEC_1_2,  4.1,  5.9},
1254 	{   QPSK, FEC_2_3,  6.1,  9.6},
1255 	{   QPSK, FEC_3_4,  7.2, 12.4},
1256 	{   QPSK, FEC_5_6,  8.5, 15.6},
1257 	{   QPSK, FEC_7_8,  9.2, 17.5},
1258 
1259 	{ QAM_16, FEC_1_2,  9.8, 11.8},
1260 	{ QAM_16, FEC_2_3, 12.1, 15.3},
1261 	{ QAM_16, FEC_3_4, 13.4, 18.1},
1262 	{ QAM_16, FEC_5_6, 14.8, 21.3},
1263 	{ QAM_16, FEC_7_8, 15.7, 23.6},
1264 
1265 	{ QAM_64, FEC_1_2, 14.0, 16.0},
1266 	{ QAM_64, FEC_2_3, 19.9, 25.4},
1267 	{ QAM_64, FEC_3_4, 24.9, 27.9},
1268 	{ QAM_64, FEC_5_6, 21.3, 23.3},
1269 	{ QAM_64, FEC_7_8, 22.0, 24.0},
1270 };
1271 
dvbv_fe_cnr_to_quality(struct dvb_v5_fe_parms_priv * parms,struct dtv_stats * cnr)1272 static enum dvb_quality dvbv_fe_cnr_to_quality(struct dvb_v5_fe_parms_priv *parms,
1273 					       struct dtv_stats *cnr)
1274 {
1275 	uint32_t modulation, fec;
1276 	enum dvb_quality qual = DVB_QUAL_UNKNOWN;
1277 
1278 	switch (cnr->scale) {
1279 	case FE_SCALE_RELATIVE:
1280 		if (cnr->uvalue == 65535)
1281 			return DVB_QUAL_GOOD;
1282 		else if (cnr->uvalue >= 65535 / 2)
1283 			return DVB_QUAL_OK;
1284 		else
1285 			return DVB_QUAL_POOR;
1286 		return qual;
1287 	case FE_SCALE_DECIBEL:
1288 		break;
1289 	default:
1290 		return DVB_QUAL_UNKNOWN;
1291 	}
1292 
1293 	switch (parms->p.current_sys) {
1294 	case SYS_DVBC_ANNEX_A:
1295 	case SYS_DVBC_ANNEX_C:
1296 		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation);
1297 		if (modulation == QAM_AUTO)
1298 			modulation = QAM_64;	/* Assume worse case */
1299 		qual = cnr_arr_to_qual(modulation, FEC_NONE, cnr->svalue,
1300 				       dvb_c_cnr_2_qual,
1301 				       ARRAY_SIZE(dvb_c_cnr_2_qual));
1302 		break;
1303 	case SYS_DVBS:
1304 		dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &fec);
1305 		qual = cnr_arr_to_qual(QPSK, fec, cnr->svalue,
1306 				       dvb_s_cnr_2_qual,
1307 				       ARRAY_SIZE(dvb_s_cnr_2_qual));
1308 		break;
1309 	case SYS_DVBS2:
1310 		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation);
1311 		dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &fec);
1312 		qual = cnr_arr_to_qual(modulation, fec, cnr->svalue,
1313 			               dvb_s2_cnr_2_qual,
1314 				       ARRAY_SIZE(dvb_s_cnr_2_qual));
1315 		break;
1316 	case SYS_ISDBT:
1317 		dvb_fe_retrieve_parm(&parms->p, DTV_ISDBT_LAYERA_MODULATION, &modulation);
1318 		dvb_fe_retrieve_parm(&parms->p, DTV_ISDBT_LAYERA_FEC, &fec);
1319 		if (modulation == QAM_AUTO)
1320 			modulation = QAM_64;	/* Assume worse case */
1321 		qual = cnr_arr_to_qual(modulation, fec, cnr->svalue,
1322 			               isdb_t_cnr_2_qual,
1323 				       ARRAY_SIZE(isdb_t_cnr_2_qual));
1324 		break;
1325 	case SYS_DVBT:
1326 		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &modulation);
1327 		dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_LP, &fec);
1328 		qual = cnr_arr_to_qual(modulation, fec, cnr->svalue,
1329 			               dvb_t_cnr_2_qual,
1330 				       ARRAY_SIZE(isdb_t_cnr_2_qual));
1331 		break;
1332 	case SYS_DVBT2:
1333 	case SYS_TURBO:
1334 	case SYS_ISDBS:
1335 	case SYS_DSS:
1336 	case SYS_DTMB:
1337 	case SYS_ATSC:
1338 	case SYS_ATSCMH:
1339 	case SYS_DVBC_ANNEX_B:
1340 	default:
1341 		/* Quality unknown */
1342 		break;
1343 	}
1344 
1345 	return qual;
1346 };
1347 
dvb_fe_retrieve_quality(struct dvb_v5_fe_parms * p,unsigned layer)1348 enum dvb_quality dvb_fe_retrieve_quality(struct dvb_v5_fe_parms *p,
1349 					 unsigned layer)
1350 {
1351 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1352 	float ber, per;
1353 	struct dtv_stats *cnr;
1354 	enum dvb_quality qual = DVB_QUAL_UNKNOWN;
1355 
1356 	per = dvb_fe_retrieve_per(&parms->p, layer);
1357 	if (per >= 0) {
1358 		if (per > 1e-6)
1359 			qual = DVB_QUAL_POOR;
1360 		else if (per > 1e-7)
1361 			return DVB_QUAL_OK;
1362 		else
1363 			return DVB_QUAL_GOOD;
1364 	}
1365 
1366 	ber = dvb_fe_retrieve_per(&parms->p, layer);
1367 	if (ber >= 0) {
1368 
1369 		if (ber > 1e-3)	/* FIXME: good enough???? */
1370 			return DVB_QUAL_POOR;
1371 
1372 		if (ber <= 2e-4)		/* BER = 10^-11 at TS */
1373 			return DVB_QUAL_GOOD;
1374 
1375 		qual = DVB_QUAL_OK;	/* OK or good */
1376 	}
1377 
1378 	cnr = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_CNR, layer);
1379 	if (cnr)
1380 		dvbv_fe_cnr_to_quality(parms, cnr);
1381 
1382 	return qual;
1383 }
1384 
dvb_fe_update_counters(struct dvb_v5_fe_parms_priv * parms)1385 static void dvb_fe_update_counters(struct dvb_v5_fe_parms_priv *parms)
1386 {
1387 	struct dtv_stats *error, *count;
1388 	int i;
1389 
1390 	for (i = 0; i < MAX_DTV_STATS; i++) {
1391 		count = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_POST_TOTAL_BIT_COUNT, i);
1392 		if (count && count->scale != FE_SCALE_NOT_AVAILABLE) {
1393 			error = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_POST_ERROR_BIT_COUNT, i);
1394 			if (!error || error->scale == FE_SCALE_NOT_AVAILABLE) {
1395 				parms->stats.has_post_ber[i] = 0;
1396 			} else if(count->uvalue != parms->stats.cur[i].post_bit_count) {
1397 				parms->stats.prev[i].post_bit_count = parms->stats.cur[i].post_bit_count;
1398 				parms->stats.cur[i].post_bit_count = count->uvalue;
1399 
1400 				parms->stats.prev[i].post_bit_error = parms->stats.cur[i].post_bit_error;
1401 				parms->stats.cur[i].post_bit_error = error->uvalue;
1402 
1403 				parms->stats.has_post_ber[i] = 1;
1404 			}
1405 		} else
1406 			parms->stats.has_post_ber[i] = 0;
1407 		count = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_PRE_TOTAL_BIT_COUNT, i);
1408 		if (count && count->scale != FE_SCALE_NOT_AVAILABLE) {
1409 			error = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_PRE_ERROR_BIT_COUNT, i);
1410 			if (!error || error->scale == FE_SCALE_NOT_AVAILABLE) {
1411 				parms->stats.has_pre_ber[i] = 0;
1412 			} else if(count->uvalue != parms->stats.cur[i].pre_bit_count) {
1413 				parms->stats.prev[i].pre_bit_count = parms->stats.cur[i].pre_bit_count;
1414 				parms->stats.cur[i].pre_bit_count = count->uvalue;
1415 
1416 				parms->stats.prev[i].pre_bit_error = parms->stats.cur[i].pre_bit_error;
1417 				parms->stats.cur[i].pre_bit_error = error->uvalue;
1418 
1419 				parms->stats.has_pre_ber[i] = 1;
1420 			}
1421 		} else
1422 			parms->stats.has_pre_ber[i] = 0;
1423 		count = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_TOTAL_BLOCK_COUNT, i);
1424 		if (count && count->scale != FE_SCALE_NOT_AVAILABLE) {
1425 			error = dvb_fe_retrieve_stats_layer(&parms->p, DTV_STAT_ERROR_BLOCK_COUNT, i);
1426 			if (!error || error->scale == FE_SCALE_NOT_AVAILABLE) {
1427 				parms->stats.has_per[i] = 0;
1428 			} else if (count->uvalue != parms->stats.cur[i].block_count) {
1429 				parms->stats.prev[i].block_count = parms->stats.cur[i].block_count;
1430 				parms->stats.cur[i].block_count = count->uvalue;
1431 
1432 				parms->stats.prev[i].block_error = parms->stats.cur[i].block_error;
1433 				parms->stats.cur[i].block_error = error->uvalue;
1434 
1435 				parms->stats.has_per[i] = 1;
1436 			}
1437 		} else
1438 			parms->stats.has_per[i] = 0;
1439 	}
1440 }
1441 
__dvb_fe_get_stats(struct dvb_v5_fe_parms * p)1442 int __dvb_fe_get_stats(struct dvb_v5_fe_parms *p)
1443 {
1444 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1445 	fe_status_t status = 0;
1446 	uint32_t ber= 0, ucb = 0;
1447 	uint16_t strength = 0, snr = 0;
1448 	int i;
1449 	enum fecap_scale_params scale;
1450 
1451 	if (xioctl(parms->fd, FE_READ_STATUS, &status) == -1) {
1452 		dvb_perror("FE_READ_STATUS");
1453 		return -EINVAL;
1454 	}
1455 	dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status);
1456 
1457 	/* if lock has obtained, get DVB parameters */
1458 	if (status != parms->stats.prev_status) {
1459 		if ((status & FE_HAS_LOCK) &&
1460 		    parms->stats.prev_status != status)
1461 			dvb_fe_get_parms(&parms->p);
1462 		parms->stats.prev_status = status;
1463 	}
1464 
1465 	if (parms->p.has_v5_stats) {
1466 		struct dtv_properties props;
1467 
1468 		props.num = DTV_NUM_KERNEL_STATS;
1469 		props.props = parms->stats.prop;
1470 
1471 		/* Do a DVBv5.10 stats call */
1472 		if (ioctl(parms->fd, FE_GET_PROPERTY, &props) == -1) {
1473 			if (errno == EAGAIN)
1474 				return 0;
1475 			goto dvbv3_fallback;
1476 		}
1477 
1478 		/*
1479 		 * All props with len=0 mean that this device doesn't have any
1480 		 * dvbv5 stats. Try the legacy stats instead.
1481 		 */
1482 		for (i = 0; i < props.num; i++)
1483 			if (parms->stats.prop[i].u.st.len)
1484 				break;
1485 		if (i == props.num)
1486 			goto dvbv3_fallback;
1487 
1488 		dvb_fe_update_counters(parms);
1489 
1490 		return 0;
1491 	}
1492 
1493 dvbv3_fallback:
1494 	/* DVB v3 stats */
1495 	parms->p.has_v5_stats = 0;
1496 
1497 	if (ioctl(parms->fd, FE_READ_BER, &ber) == -1)
1498 		scale = FE_SCALE_NOT_AVAILABLE;
1499 	else
1500 		scale = FE_SCALE_RELATIVE;
1501 
1502 	/*
1503 	 * BER scale on DVBv3 is not defined - different drivers use
1504 	 * different scales, even weird ones, like multiples of 1/65280
1505 	 */
1506 	dvb_fe_store_stats(parms, DTV_BER, scale, 0, ber);
1507 
1508 	if (ioctl(parms->fd, FE_READ_SIGNAL_STRENGTH, &strength) == -1)
1509 		scale = FE_SCALE_NOT_AVAILABLE;
1510 	else
1511 		scale = FE_SCALE_RELATIVE;
1512 
1513 	dvb_fe_store_stats(parms, DTV_STAT_SIGNAL_STRENGTH, scale, 0, strength);
1514 
1515 	if (ioctl(parms->fd, FE_READ_SNR, &snr) == -1)
1516 		scale = FE_SCALE_NOT_AVAILABLE;
1517 	else
1518 		scale = FE_SCALE_RELATIVE;
1519 	dvb_fe_store_stats(parms, DTV_STAT_CNR, scale, 0, snr);
1520 
1521 	if (ioctl(parms->fd, FE_READ_UNCORRECTED_BLOCKS, &ucb) == -1)
1522 		scale = FE_SCALE_NOT_AVAILABLE;
1523 	else
1524 		scale = FE_SCALE_COUNTER;
1525 	dvb_fe_store_stats(parms, DTV_STAT_ERROR_BLOCK_COUNT, scale, 0, snr);
1526 
1527 	if (parms->p.verbose > 1) {
1528 		dvb_log(_("Status: "));
1529 		for (i = 0; i < ARRAY_SIZE(fe_status_name); i++) {
1530 			if (status & fe_status_name[i].idx)
1531 				dvb_log ("    %s", fe_status_name[i].name);
1532 		}
1533 		dvb_log(_("BER: %d, Strength: %d, SNR: %d, UCB: %d"),
1534 		       ber, strength, snr, ucb);
1535 	}
1536 	return 0;
1537 }
1538 
1539 
dvb_fe_get_event(struct dvb_v5_fe_parms * p)1540 int dvb_fe_get_event(struct dvb_v5_fe_parms *p)
1541 {
1542 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1543 	struct dvb_frontend_event event;
1544 	fe_status_t status;
1545 	int i;
1546 
1547 	if (!parms->p.legacy_fe) {
1548 		dvb_fe_get_parms(&parms->p);
1549 		return dvb_fe_get_stats(&parms->p);
1550 	}
1551 
1552 	if (xioctl(parms->fd, FE_GET_EVENT, &event) == -1) {
1553 		dvb_perror("FE_GET_EVENT");
1554 		return -errno;
1555 	}
1556 	status = event.status;
1557 	if (parms->p.verbose > 1) {
1558 		dvb_log(_("Status: "));
1559 		for (i = 0; i < ARRAY_SIZE(fe_status_name); i++) {
1560 			if (status & fe_status_name[i].idx)
1561 				dvb_log ("    %s", fe_status_name[i].name);
1562 		}
1563 	}
1564 	dvb_fe_store_stats(parms, DTV_STATUS, FE_SCALE_RELATIVE, 0, status);
1565 
1566 	dvb_fe_retrieve_parm(&parms->p, DTV_FREQUENCY, &event.parameters.frequency);
1567 	dvb_fe_retrieve_parm(&parms->p, DTV_INVERSION, &event.parameters.inversion);
1568 	switch (parms->p.current_sys) {
1569 	case SYS_DVBS:
1570 		dvb_fe_retrieve_parm(&parms->p, DTV_SYMBOL_RATE, &event.parameters.u.qpsk.symbol_rate);
1571 		dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &event.parameters.u.qpsk.fec_inner);
1572 		break;
1573 	case SYS_DVBC_ANNEX_AC:
1574 		dvb_fe_retrieve_parm(&parms->p, DTV_SYMBOL_RATE, &event.parameters.u.qam.symbol_rate);
1575 		dvb_fe_retrieve_parm(&parms->p, DTV_INNER_FEC, &event.parameters.u.qam.fec_inner);
1576 		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.qam.modulation);
1577 		break;
1578 	case SYS_ATSC:
1579 	case SYS_ATSCMH:
1580 	case SYS_DVBC_ANNEX_B:
1581 		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.vsb.modulation);
1582 		break;
1583 	case SYS_DVBT:
1584 		dvb_fe_retrieve_parm(&parms->p, DTV_BANDWIDTH_HZ, &event.parameters.u.ofdm.bandwidth);
1585 		dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_HP, &event.parameters.u.ofdm.code_rate_HP);
1586 		dvb_fe_retrieve_parm(&parms->p, DTV_CODE_RATE_LP, &event.parameters.u.ofdm.code_rate_LP);
1587 		dvb_fe_retrieve_parm(&parms->p, DTV_MODULATION, &event.parameters.u.ofdm.constellation);
1588 		dvb_fe_retrieve_parm(&parms->p, DTV_TRANSMISSION_MODE, &event.parameters.u.ofdm.transmission_mode);
1589 		dvb_fe_retrieve_parm(&parms->p, DTV_GUARD_INTERVAL, &event.parameters.u.ofdm.guard_interval);
1590 		dvb_fe_retrieve_parm(&parms->p, DTV_HIERARCHY, &event.parameters.u.ofdm.hierarchy_information);
1591 		break;
1592 	default:
1593 		return -EINVAL;
1594 	}
1595 
1596 	return dvb_fe_get_stats(&parms->p);
1597 }
1598 
1599 struct metric_prefixes {
1600 	int multiply_factor;
1601 	char *symbol;
1602 };
1603 
1604 static struct metric_prefixes prefixes[] = {
1605 	{  24, "Y" },
1606 	{  21, "Z" },
1607 	{  18, "E" },
1608 	{  15, "P" },
1609 	{  12, "T" },
1610 	{   9, "G" },
1611 	{   6, "M" },
1612 	{   3, "k" },
1613 	{  -3, "m" },
1614 	{  -6, "μ" },
1615 	{  -9, "n" },
1616 	{ -12, "p" },
1617 	{ -15, "f" },
1618 	{ -18, "a" },
1619 	{ -21, "z" },
1620 	{ -24, "y" },
1621 };
1622 
__dvb_fe_snprintf_eng(char * buf,int len,float val,int metric)1623 static int __dvb_fe_snprintf_eng(char *buf, int len, float val, int metric)
1624 {
1625 	int digits = 3;
1626 	int exp, signal = 1, i;
1627 
1628 	/* If value is zero, nothing to do */
1629 	if (val == 0.)
1630 		return snprintf(buf, len, " 0");
1631 
1632 	/* Take the absolute value */
1633 	if (val < 0.) {
1634 		signal = -1;
1635 		val = -val;
1636 	}
1637 
1638 	/*
1639 	 * Converts the number into an expoent and a
1640 	 * value between 0 and 1000, exclusive
1641 	 */
1642 	exp = (int)log10f(val);
1643 	if (exp > 0)
1644 		exp = (exp / 3) * 3;
1645 	else
1646 		exp = (-exp + 3) / 3 * (-3);
1647 
1648 	val *= pow(10, -exp);
1649 
1650 	if (val >= 1000.) {
1651 		val /= 1000.0;
1652 		exp += 3;
1653 	} else if(val >= 100.0)
1654 		digits -= 2;
1655 	else if(val >= 10.0)
1656 		digits -= 1;
1657 
1658 	if (exp) {
1659 		if (metric) {
1660 			for (i = 0; i < ARRAY_SIZE(prefixes); i++) {
1661 				if (exp == prefixes[i].multiply_factor)
1662 					return snprintf(buf, len, " %.*f %s", digits - 1,
1663 		                                        val, prefixes[i].symbol);
1664 			}
1665 			/* Fall back to normal handling */
1666 		}
1667 		if (signal > 0)
1668 			return snprintf(buf, len, " %.*fx10^%d", digits - 1,
1669 					val, exp);
1670 
1671 		return snprintf(buf, len, " -%.*fx10^%d", digits - 1,
1672 					val, exp);
1673 	}
1674 
1675 	if (signal > 0)
1676 		return snprintf(buf, len, " %.*f", digits - 1, val);
1677 
1678 	return snprintf(buf, len, " -%.*f", digits - 1, val);
1679 }
1680 
dvb_fe_snprintf_eng(char * buf,int len,float val)1681 int dvb_fe_snprintf_eng(char *buf, int len, float val)
1682 {
1683 	return __dvb_fe_snprintf_eng(buf, len, val, 0);
1684 }
1685 
1686 static char *sig_bits[7] = {
1687 	[0] = N_("RF"),
1688 	[1] = N_("Carrier"),
1689 	[2] = N_("Viterbi"),
1690 	[3] = N_("Sync"),
1691 	[4] = N_("Lock"),
1692 	[5] = N_("Timeout"),
1693 	[6] = N_("Reinit"),
1694 };
1695 
1696 static char *qual_name[] = {
1697 	[DVB_QUAL_POOR] = N_("Poor"),
1698 	[DVB_QUAL_OK]   = N_("Ok"),
1699 	[DVB_QUAL_GOOD] = N_("Good"),
1700 };
1701 
dvb_fe_snprintf_stat(struct dvb_v5_fe_parms * p,uint32_t cmd,char * display_name,int layer,char ** buf,int * len,int * show_layer_name)1702 int dvb_fe_snprintf_stat(struct dvb_v5_fe_parms *p, uint32_t cmd,
1703 			  char *display_name, int layer,
1704 		          char **buf, int *len, int *show_layer_name)
1705 {
1706 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1707 	struct dtv_stats *stat = NULL;
1708 	enum dvb_quality qual = DVB_QUAL_UNKNOWN;
1709 	enum fecap_scale_params scale;
1710 	float val = -1;
1711 	int initial_len = *len;
1712 	int size, i;
1713 
1714 	/* Print status, if layer == 0, as there is only global status */
1715 	if (cmd == DTV_STATUS) {
1716 		fe_status_t status;
1717 
1718 		if (layer)
1719 			return 0;
1720 
1721 		if (dvb_fe_retrieve_stats(&parms->p, DTV_STATUS, &status)) {
1722 			dvb_logerr (_("Error: no adapter status"));
1723 			return -EINVAL;
1724 		}
1725 		if (display_name) {
1726 			size = snprintf(*buf, *len, " %s=", display_name);
1727 			*buf += size;
1728 			*len -= size;
1729 		}
1730 
1731 		/* Get the name of the highest status bit */
1732 		for (i = ARRAY_SIZE(sig_bits) - 1; i >= 0 ; i--) {
1733 			if ((1 << i) & status) {
1734 				size = snprintf(*buf, *len, _("%-7s"), _(sig_bits[i]));
1735 				*buf += size;
1736 				*len -= size;
1737 				break;
1738 			}
1739 		}
1740 		if (i < 0) {
1741 			size = snprintf(*buf, *len, _("%7s"), "");
1742 			*buf += size;
1743 			*len -= size;
1744 		}
1745 
1746 		/* Add the status bits */
1747 		size = snprintf(*buf, *len, "(0x%02x)", status);
1748 		*buf += size;
1749 		*len -= size;
1750 
1751 		return initial_len - *len;
1752 	}
1753 
1754 	/* Retrieve the statistics */
1755 	switch (cmd) {
1756 	case DTV_PRE_BER:
1757 		val = calculate_preBER(parms, layer);
1758 		if (val < 0)
1759 			return 0;
1760 		scale = FE_SCALE_COUNTER;
1761 		break;
1762 	case DTV_BER:
1763 		val = dvb_fe_retrieve_ber(&parms->p, layer, &scale);
1764 		if (scale == FE_SCALE_NOT_AVAILABLE)
1765 			return 0;
1766 		break;
1767 	case DTV_PER:
1768 		val = dvb_fe_retrieve_per(&parms->p, layer);
1769 		if (val < 0)
1770 			return 0;
1771 		scale = FE_SCALE_COUNTER;
1772 		break;
1773 	case DTV_QUALITY:
1774 		qual = dvb_fe_retrieve_quality(&parms->p, layer);
1775 		if (qual == DVB_QUAL_UNKNOWN)
1776 			return 0;
1777 		break;
1778 	default:
1779 		stat = dvb_fe_retrieve_stats_layer(&parms->p, cmd, layer);
1780 		if (!stat || stat->scale == FE_SCALE_NOT_AVAILABLE)
1781 			return 0;
1782 	}
1783 
1784 	/* If requested, prints the layer name */
1785 	if (*show_layer_name && layer) {
1786 		size = snprintf(*buf, *len, _("  Layer %c:"), 'A' + layer - 1);
1787 		*buf += size;
1788 		*len -= size;
1789 		*show_layer_name = 0;
1790 	}
1791 	if (display_name) {
1792 		size = snprintf(*buf, *len, " %s=", display_name);
1793 		*buf += size;
1794 		*len -= size;
1795 	}
1796 
1797 	/* Quality measure */
1798 	if (qual != DVB_QUAL_UNKNOWN) {
1799 		size = snprintf(*buf, *len, " %-4s", _(qual_name[qual]));
1800 		*buf += size;
1801 		*len -= size;
1802 		return initial_len - *len;
1803 	}
1804 
1805 
1806 	/* Special case: float point measures like BER/PER */
1807 	if (!stat) {
1808 		switch (scale) {
1809 		case FE_SCALE_RELATIVE:
1810 			size = snprintf(*buf, *len, " %u", (unsigned int)val);
1811 			break;
1812 		case FE_SCALE_COUNTER:
1813 			size = dvb_fe_snprintf_eng(*buf, *len, val);
1814 			break;
1815 		default:
1816 			size = 0;
1817 		}
1818 		*buf += size;
1819 		*len -= size;
1820 		return initial_len - *len;
1821 	}
1822 
1823 	/* Prints the scale */
1824 	switch (stat->scale) {
1825 	case FE_SCALE_DECIBEL:
1826 		if (cmd == DTV_STAT_SIGNAL_STRENGTH)
1827 			size = snprintf(*buf, *len, " %.2fdBm", stat->svalue / 1000.);
1828 		else
1829 			size = snprintf(*buf, *len, " %.2fdB", stat->svalue / 1000.);
1830 		break;
1831 	case FE_SCALE_RELATIVE:
1832 		size = snprintf(*buf, *len, " %3.2f%%", (100 * stat->uvalue) / 65535.);
1833 		break;
1834 	case FE_SCALE_COUNTER:
1835 		size = snprintf(*buf, *len, " %" PRIu64, (uint64_t)stat->uvalue);
1836 		break;
1837 	default:
1838 		size = 0;
1839 	}
1840 	*buf += size;
1841 	*len -= size;
1842 
1843 	return initial_len - *len;
1844 }
1845 
1846 /*
1847  * Implement SEC/LNB/DISEqC specific functions
1848  * For now, DVBv5 API doesn't support those commands. So, use the DVBv3
1849  * version.
1850  */
1851 
dvb_fe_sec_voltage(struct dvb_v5_fe_parms * p,int on,int v18)1852 int dvb_fe_sec_voltage(struct dvb_v5_fe_parms *p, int on, int v18)
1853 {
1854 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1855 	fe_sec_voltage_t v;
1856 	int rc;
1857 
1858 	if (!on) {
1859 		v = SEC_VOLTAGE_OFF;
1860 		if (parms->p.verbose)
1861 			dvb_log(_("SEC: set voltage to OFF"));
1862 	} else {
1863 		v = v18 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13;
1864 		if (parms->p.verbose)
1865 			dvb_log(_("SEC: set voltage to %sV"), v18 ? "18" : "13");
1866 	}
1867 	rc = xioctl(parms->fd, FE_SET_VOLTAGE, v);
1868 	if (rc == -1) {
1869 		if (errno == ENOTSUP) {
1870 			dvb_logerr("FE_SET_VOLTAGE: driver doesn't support it!");
1871 		} else {
1872 			dvb_perror("FE_SET_VOLTAGE");
1873 		}
1874 		return -errno;
1875 	}
1876 	return rc;
1877 }
1878 
dvb_fe_sec_tone(struct dvb_v5_fe_parms * p,fe_sec_tone_mode_t tone)1879 int dvb_fe_sec_tone(struct dvb_v5_fe_parms *p, fe_sec_tone_mode_t tone)
1880 {
1881 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1882 	int rc;
1883 	if (parms->p.verbose)
1884 		dvb_log( _("DiSEqC TONE: %s"), fe_tone_name[tone] );
1885 	rc = xioctl(parms->fd, FE_SET_TONE, tone);
1886 	if (rc == -1) {
1887 		dvb_perror("FE_SET_TONE");
1888 		return -errno;
1889 	}
1890 	return rc;
1891 }
1892 
dvb_fe_lnb_high_voltage(struct dvb_v5_fe_parms * p,int on)1893 int dvb_fe_lnb_high_voltage(struct dvb_v5_fe_parms *p, int on)
1894 {
1895 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1896 	int rc;
1897 
1898 	if (on) on = 1;
1899 	if (parms->p.verbose)
1900 		dvb_log( _("DiSEqC HIGH LNB VOLTAGE: %s"), on ? _("ON") : _("OFF") );
1901 	rc = xioctl(parms->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, on);
1902 	if (rc == -1) {
1903 		dvb_perror("FE_ENABLE_HIGH_LNB_VOLTAGE");
1904 		return -errno;
1905 	}
1906 	return rc;
1907 }
1908 
dvb_fe_diseqc_burst(struct dvb_v5_fe_parms * p,int mini_b)1909 int dvb_fe_diseqc_burst(struct dvb_v5_fe_parms *p, int mini_b)
1910 {
1911 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1912 	fe_sec_mini_cmd_t mini;
1913 	int rc;
1914 
1915 	mini = mini_b ? SEC_MINI_B : SEC_MINI_A;
1916 
1917 	if (parms->p.verbose)
1918 		dvb_log( _("DiSEqC BURST: %s"), mini_b ? "SEC_MINI_B" : "SEC_MINI_A" );
1919 	rc = xioctl(parms->fd, FE_DISEQC_SEND_BURST, mini);
1920 	if (rc == -1) {
1921 		dvb_perror("FE_DISEQC_SEND_BURST");
1922 		return -errno;
1923 	}
1924 	return rc;
1925 }
1926 
dvb_fe_diseqc_cmd(struct dvb_v5_fe_parms * p,const unsigned len,const unsigned char * buf)1927 int dvb_fe_diseqc_cmd(struct dvb_v5_fe_parms *p, const unsigned len,
1928 		      const unsigned char *buf)
1929 {
1930 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1931 	struct dvb_diseqc_master_cmd msg;
1932 	int rc;
1933 
1934 	if (len > 6)
1935 		return -EINVAL;
1936 
1937 	msg.msg_len = len;
1938 	memcpy(msg.msg, buf, len);
1939 
1940 	if (parms->p.verbose) {
1941 		int i;
1942 		char log[len * 3 + 20], *p = log;
1943 
1944 		p += sprintf(p, _("DiSEqC command: "));
1945 		for (i = 0; i < len; i++)
1946 			p += sprintf (p, "%02x ", buf[i]);
1947 		dvb_log("%s", log);
1948 	}
1949 
1950 	rc = xioctl(parms->fd, FE_DISEQC_SEND_MASTER_CMD, &msg);
1951 	if (rc == -1) {
1952 		dvb_perror("FE_DISEQC_SEND_MASTER_CMD");
1953 		return -errno;
1954 	}
1955 	return rc;
1956 }
1957 
dvb_fe_diseqc_reply(struct dvb_v5_fe_parms * p,unsigned * len,char * buf,int timeout)1958 int dvb_fe_diseqc_reply(struct dvb_v5_fe_parms *p, unsigned *len, char *buf,
1959 		       int timeout)
1960 {
1961 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1962 	struct dvb_diseqc_slave_reply reply;
1963 	int rc;
1964 
1965 	if (*len > 4)
1966 		*len = 4;
1967 
1968 	reply.timeout = timeout;
1969 	reply.msg_len = *len;
1970 
1971 	if (parms->p.verbose)
1972 		dvb_log("DiSEqC FE_DISEQC_RECV_SLAVE_REPLY");
1973 
1974 	rc = xioctl(parms->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply);
1975 	if (rc == -1) {
1976 		dvb_perror("FE_DISEQC_RECV_SLAVE_REPLY");
1977 		return -errno;
1978 	}
1979 
1980 	*len = reply.msg_len;
1981 	memcpy(buf, reply.msg, reply.msg_len);
1982 
1983 	return 0;
1984 }
1985 
dvb_fe_set_default_country(struct dvb_v5_fe_parms * p,const char * cc)1986 int dvb_fe_set_default_country(struct dvb_v5_fe_parms *p, const char *cc)
1987 {
1988 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
1989 
1990 	if (!cc) {
1991 		parms->country = dvb_guess_user_country();
1992 		if (parms->p.verbose) {
1993 			if (parms->country != COUNTRY_UNKNOWN)
1994 				dvb_log(_("Assuming you're in %s.\n"),
1995 					dvb_country_to_2letters(parms->country));
1996 			else
1997 				dvb_log(_("Failed to guess country from the current locale setting.\n"));
1998 		}
1999 		return 0;
2000 	}
2001 
2002 	parms->country = dvb_country_a2_to_id(cc);
2003 	return (parms->country == COUNTRY_UNKNOWN) ? -EINVAL : 0;
2004 }
2005 
dvb_get_log_priv(struct dvb_v5_fe_parms * p,void ** priv)2006 dvb_logfunc_priv dvb_get_log_priv(struct dvb_v5_fe_parms *p, void **priv)
2007 {
2008 	struct dvb_v5_fe_parms_priv *parms = (void *)p;
2009 	*priv = parms->logpriv;
2010 	return parms->logfunc_priv;
2011 }
2012