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