1 /*
2  * libdvbfe - a DVB frontend library
3  *
4  * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
5  * Copyright (C) 2005 Manu Abraham <abraham.manu@gmail.com>
6  * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
21  */
22 
23 #define _GNU_SOURCE
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <sys/param.h>
28 #include <sys/ioctl.h>
29 #include <sys/time.h>
30 #include <sys/poll.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <linux/dvb/frontend.h>
36 #include <libdvbmisc/dvbmisc.h>
37 #include "dvbfe.h"
38 
39 int verbose = 0;
40 
41 static int dvbfe_spectral_inversion_to_kapi[][2] =
42 {
43 	{ DVBFE_INVERSION_OFF, INVERSION_OFF },
44 	{ DVBFE_INVERSION_ON, INVERSION_ON },
45 	{ DVBFE_INVERSION_AUTO, INVERSION_AUTO },
46 	{ -1, -1 }
47 };
48 
49 static int dvbfe_code_rate_to_kapi[][2] =
50 {
51 	{ DVBFE_FEC_NONE, FEC_NONE },
52 	{ DVBFE_FEC_1_2, FEC_1_2 },
53 	{ DVBFE_FEC_2_3, FEC_2_3 },
54 	{ DVBFE_FEC_3_4, FEC_3_4 },
55 	{ DVBFE_FEC_4_5, FEC_4_5 },
56 	{ DVBFE_FEC_5_6, FEC_5_6 },
57 	{ DVBFE_FEC_6_7, FEC_6_7 },
58 	{ DVBFE_FEC_7_8, FEC_7_8 },
59 	{ DVBFE_FEC_8_9, FEC_8_9 },
60 	{ DVBFE_FEC_AUTO, FEC_AUTO },
61 	{ -1, -1 }
62 };
63 
64 static int dvbfe_dvbt_const_to_kapi[][2] =
65 {
66 	{ DVBFE_DVBT_CONST_QPSK, FE_QPSK },
67 	{ DVBFE_DVBT_CONST_QAM_16, QAM_16 },
68 	{ DVBFE_DVBT_CONST_QAM_32, QAM_32 },
69 	{ DVBFE_DVBT_CONST_QAM_64, QAM_64 },
70 	{ DVBFE_DVBT_CONST_QAM_128, QAM_128 },
71 	{ DVBFE_DVBT_CONST_QAM_256, QAM_256 },
72 	{ DVBFE_DVBT_CONST_AUTO, QAM_AUTO },
73 	{ -1, -1 }
74 };
75 
76 static int dvbfe_dvbc_mod_to_kapi[][2] =
77 {
78 	{ DVBFE_DVBC_MOD_QAM_16, QAM_16 },
79 	{ DVBFE_DVBC_MOD_QAM_32, QAM_32 },
80 	{ DVBFE_DVBC_MOD_QAM_64, QAM_64 },
81 	{ DVBFE_DVBC_MOD_QAM_128, QAM_128 },
82 	{ DVBFE_DVBC_MOD_QAM_256, QAM_256 },
83 	{ DVBFE_DVBC_MOD_AUTO, QAM_AUTO },
84 	{ -1, -1 }
85 };
86 
87 static int dvbfe_atsc_mod_to_kapi[][2] =
88 {
89 	{ DVBFE_ATSC_MOD_QAM_64, QAM_64 },
90 	{ DVBFE_ATSC_MOD_QAM_256, QAM_256 },
91 	{ DVBFE_ATSC_MOD_VSB_8, VSB_8 },
92 	{ DVBFE_ATSC_MOD_VSB_16, VSB_16 },
93 	{ DVBFE_ATSC_MOD_AUTO, QAM_AUTO },
94 	{ -1, -1 }
95 };
96 
97 static int dvbfe_dvbt_transmit_mode_to_kapi[][2] =
98 {
99 	{ DVBFE_DVBT_TRANSMISSION_MODE_2K, TRANSMISSION_MODE_2K },
100 	{ DVBFE_DVBT_TRANSMISSION_MODE_8K, TRANSMISSION_MODE_8K },
101 	{ DVBFE_DVBT_TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO },
102 	{ -1, -1 }
103 };
104 
105 static int dvbfe_dvbt_bandwidth_to_kapi[][2] =
106 {
107 	{ DVBFE_DVBT_BANDWIDTH_8_MHZ, BANDWIDTH_8_MHZ },
108 	{ DVBFE_DVBT_BANDWIDTH_7_MHZ, BANDWIDTH_7_MHZ },
109 	{ DVBFE_DVBT_BANDWIDTH_6_MHZ, BANDWIDTH_6_MHZ },
110 	{ DVBFE_DVBT_BANDWIDTH_AUTO, BANDWIDTH_AUTO },
111 	{ -1, -1 }
112 };
113 
114 static int dvbfe_dvbt_guard_interval_to_kapi[][2] =
115 {
116 	{ DVBFE_DVBT_GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_32},
117 	{ DVBFE_DVBT_GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_16},
118 	{ DVBFE_DVBT_GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_8},
119 	{ DVBFE_DVBT_GUARD_INTERVAL_1_4, GUARD_INTERVAL_1_4},
120 	{ DVBFE_DVBT_GUARD_INTERVAL_AUTO, GUARD_INTERVAL_AUTO},
121 	{ -1, -1 }
122 };
123 
124 static int dvbfe_dvbt_hierarchy_to_kapi[][2] =
125 {
126 	{ DVBFE_DVBT_HIERARCHY_NONE, HIERARCHY_NONE },
127 	{ DVBFE_DVBT_HIERARCHY_1, HIERARCHY_1 },
128 	{ DVBFE_DVBT_HIERARCHY_2, HIERARCHY_2 },
129 	{ DVBFE_DVBT_HIERARCHY_4, HIERARCHY_4 },
130 	{ DVBFE_DVBT_HIERARCHY_AUTO, HIERARCHY_AUTO },
131 	{ -1, -1 }
132 };
133 
134 
lookupval(int val,int reverse,int table[][2])135 static int lookupval(int val, int reverse, int table[][2])
136 {
137 	int i =0;
138 
139 	while(table[i][0] != -1) {
140 		if (!reverse) {
141 			if (val == table[i][0]) {
142 				return table[i][1];
143 			}
144 		} else {
145 			if (val == table[i][1]) {
146 				return table[i][0];
147 			}
148 		}
149 		i++;
150 	}
151 
152 	return -1;
153 }
154 
155 
156 struct dvbfe_handle {
157 	int fd;
158 	enum dvbfe_type type;
159 	char *name;
160 };
161 
dvbfe_open(int adapter,int frontend,int readonly)162 struct dvbfe_handle *dvbfe_open(int adapter, int frontend, int readonly)
163 {
164 	char filename[PATH_MAX+1];
165 	struct dvbfe_handle *fehandle;
166 	int fd;
167 	struct dvb_frontend_info info;
168 
169 	//  flags
170 	int flags = O_RDWR;
171 	if (readonly) {
172 		flags = O_RDONLY;
173 	}
174 
175 	// open it (try normal /dev structure first)
176 	sprintf(filename, "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
177 	if ((fd = open(filename, flags)) < 0) {
178 		// if that failed, try a flat /dev structure
179 		sprintf(filename, "/dev/dvb%i.frontend%i", adapter, frontend);
180 		if ((fd = open(filename, flags)) < 0) {
181 			return NULL;
182 		}
183 	}
184 
185 	// determine fe type
186 	if (ioctl(fd, FE_GET_INFO, &info)) {
187 		close(fd);
188 		return NULL;
189 	}
190 
191 	// setup structure
192 	fehandle = (struct dvbfe_handle*) malloc(sizeof(struct dvbfe_handle));
193 	memset(fehandle, 0, sizeof(struct dvbfe_handle));
194 	fehandle->fd = fd;
195 	switch(info.type) {
196 	case FE_QPSK:
197 		fehandle->type = DVBFE_TYPE_DVBS;
198 		break;
199 
200 	case FE_QAM:
201 		fehandle->type = DVBFE_TYPE_DVBC;
202 		break;
203 
204 	case FE_OFDM:
205 		fehandle->type = DVBFE_TYPE_DVBT;
206 		break;
207 
208 	case FE_ATSC:
209 		fehandle->type = DVBFE_TYPE_ATSC;
210 		break;
211 	}
212 	fehandle->name = strndup(info.name, sizeof(info.name));
213 
214 	// done
215 	return fehandle;
216 }
217 
dvbfe_close(struct dvbfe_handle * fehandle)218 void dvbfe_close(struct dvbfe_handle *fehandle)
219 {
220 	close(fehandle->fd);
221 	free(fehandle->name);
222 	free(fehandle);
223 }
224 
dvbfe_get_info(struct dvbfe_handle * fehandle,enum dvbfe_info_mask querymask,struct dvbfe_info * result,enum dvbfe_info_querytype querytype,int timeout)225 extern int dvbfe_get_info(struct dvbfe_handle *fehandle,
226 			  enum dvbfe_info_mask querymask,
227 			  struct dvbfe_info *result,
228 			  enum dvbfe_info_querytype querytype,
229 			  int timeout)
230 {
231 	int returnval = 0;
232 	struct dvb_frontend_event kevent;
233 	int ok = 0;
234 
235 	result->name = fehandle->name;
236 	result->type = fehandle->type;
237 
238 	switch(querytype) {
239 	case DVBFE_INFO_QUERYTYPE_IMMEDIATE:
240 		if (querymask & DVBFE_INFO_LOCKSTATUS) {
241 			if (!ioctl(fehandle->fd, FE_READ_STATUS, &kevent.status)) {
242 				returnval |= DVBFE_INFO_LOCKSTATUS;
243 			}
244 		}
245 		if (querymask & DVBFE_INFO_FEPARAMS) {
246 			if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kevent.parameters)) {
247 				returnval |= DVBFE_INFO_FEPARAMS;
248 			}
249 		}
250 		break;
251 
252 	case DVBFE_INFO_QUERYTYPE_LOCKCHANGE:
253 		{
254 			struct pollfd pollfd;
255 			pollfd.fd = fehandle->fd;
256 			pollfd.events = POLLIN | POLLERR;
257 
258 			ok = 1;
259 			if (poll(&pollfd, 1, timeout) < 0)
260 				ok = 0;
261 			if (pollfd.revents & POLLERR)
262 				ok = 0;
263 			if (!(pollfd.revents & POLLIN))
264 				ok = 0;
265 		}
266 
267 		if (ok &&
268 		    ((querymask & DVBFE_INFO_LOCKSTATUS) ||
269 		     (querymask & DVBFE_INFO_FEPARAMS))) {
270 			if (!ioctl(fehandle->fd, FE_GET_EVENT, &kevent)) {
271 				if (querymask & DVBFE_INFO_LOCKSTATUS)
272 					returnval |= DVBFE_INFO_LOCKSTATUS;
273 				if (querymask & DVBFE_INFO_FEPARAMS)
274 					returnval |= DVBFE_INFO_FEPARAMS;
275 			}
276 		}
277 		break;
278 	}
279 
280 	if (returnval & DVBFE_INFO_LOCKSTATUS) {
281 		result->signal = kevent.status & FE_HAS_SIGNAL ? 1 : 0;
282 		result->carrier = kevent.status & FE_HAS_CARRIER ? 1 : 0;
283 		result->viterbi = kevent.status & FE_HAS_VITERBI ? 1 : 0;
284 		result->sync = kevent.status & FE_HAS_SYNC ? 1 : 0;
285 		result->lock = kevent.status & FE_HAS_LOCK ? 1 : 0;
286 	}
287 
288 	if (returnval & DVBFE_INFO_FEPARAMS) {
289 		result->feparams.frequency = kevent.parameters.frequency;
290 		result->feparams.inversion = lookupval(kevent.parameters.inversion, 1, dvbfe_spectral_inversion_to_kapi);
291 		switch(fehandle->type) {
292 		case FE_QPSK:
293 			result->feparams.u.dvbs.symbol_rate = kevent.parameters.u.qpsk.symbol_rate;
294 			result->feparams.u.dvbs.fec_inner =
295 				lookupval(kevent.parameters.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi);
296 			break;
297 
298 		case FE_QAM:
299 			result->feparams.u.dvbc.symbol_rate = kevent.parameters.u.qam.symbol_rate;
300 			result->feparams.u.dvbc.fec_inner =
301 				lookupval(kevent.parameters.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi);
302 			result->feparams.u.dvbc.modulation =
303 				lookupval(kevent.parameters.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi);
304 			break;
305 
306 		case FE_OFDM:
307 			result->feparams.u.dvbt.bandwidth =
308 				lookupval(kevent.parameters.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi);
309 			result->feparams.u.dvbt.code_rate_HP =
310 				lookupval(kevent.parameters.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi);
311 			result->feparams.u.dvbt.code_rate_LP =
312 				lookupval(kevent.parameters.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi);
313 			result->feparams.u.dvbt.constellation =
314 				lookupval(kevent.parameters.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi);
315 			result->feparams.u.dvbt.transmission_mode =
316 				lookupval(kevent.parameters.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi);
317 			result->feparams.u.dvbt.guard_interval =
318 				lookupval(kevent.parameters.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi);
319 			result->feparams.u.dvbt.hierarchy_information =
320 				lookupval(kevent.parameters.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi);
321 			break;
322 
323 		case FE_ATSC:
324 			result->feparams.u.atsc.modulation =
325 				lookupval(kevent.parameters.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi);
326 			break;
327 		}
328 	}
329 
330 	if (querymask & DVBFE_INFO_BER) {
331 		if (!ioctl(fehandle->fd, FE_READ_BER, &result->ber))
332 			returnval |= DVBFE_INFO_BER;
333 	}
334 	if (querymask & DVBFE_INFO_SIGNAL_STRENGTH) {
335 		if (!ioctl(fehandle->fd, FE_READ_SIGNAL_STRENGTH, &result->signal_strength))
336 			returnval |= DVBFE_INFO_SIGNAL_STRENGTH;
337 	}
338 	if (querymask & DVBFE_INFO_SNR) {
339 		if (!ioctl(fehandle->fd, FE_READ_SNR, &result->snr))
340 			returnval |= DVBFE_INFO_SNR;
341 	}
342 	if (querymask & DVBFE_INFO_UNCORRECTED_BLOCKS) {
343 		if (!ioctl(fehandle->fd, FE_READ_UNCORRECTED_BLOCKS, &result->ucblocks))
344 			returnval |= DVBFE_INFO_UNCORRECTED_BLOCKS;
345 	}
346 
347 	// done
348 	return returnval;
349 }
350 
dvbfe_set(struct dvbfe_handle * fehandle,struct dvbfe_parameters * params,int timeout)351 int dvbfe_set(struct dvbfe_handle *fehandle,
352 	      struct dvbfe_parameters *params,
353 	      int timeout)
354 {
355 	struct dvb_frontend_parameters kparams;
356 	int res;
357 	struct timeval endtime;
358 	fe_status_t status;
359 
360 	kparams.frequency = params->frequency;
361 	kparams.inversion = lookupval(params->inversion, 0, dvbfe_spectral_inversion_to_kapi);
362 	switch(fehandle->type) {
363 	case FE_QPSK:
364 		kparams.u.qpsk.symbol_rate = params->u.dvbs.symbol_rate;
365 		kparams.u.qpsk.fec_inner = lookupval(params->u.dvbs.fec_inner, 0, dvbfe_code_rate_to_kapi);
366 		break;
367 
368 	case FE_QAM:
369 		kparams.u.qam.symbol_rate = params->u.dvbc.symbol_rate;
370 		kparams.u.qam.fec_inner = lookupval(params->u.dvbc.fec_inner, 0, dvbfe_code_rate_to_kapi);
371 		kparams.u.qam.modulation = lookupval(params->u.dvbc.modulation, 0, dvbfe_dvbc_mod_to_kapi);
372 		break;
373 
374 	case FE_OFDM:
375 		kparams.u.ofdm.bandwidth = lookupval(params->u.dvbt.bandwidth, 0, dvbfe_dvbt_bandwidth_to_kapi);
376 		kparams.u.ofdm.code_rate_HP = lookupval(params->u.dvbt.code_rate_HP, 0, dvbfe_code_rate_to_kapi);
377 		kparams.u.ofdm.code_rate_LP = lookupval(params->u.dvbt.code_rate_LP, 0, dvbfe_code_rate_to_kapi);
378 		kparams.u.ofdm.constellation = lookupval(params->u.dvbt.constellation, 0, dvbfe_dvbt_const_to_kapi);
379 		kparams.u.ofdm.transmission_mode =
380 			lookupval(params->u.dvbt.transmission_mode, 0, dvbfe_dvbt_transmit_mode_to_kapi);
381 		kparams.u.ofdm.guard_interval =
382 			lookupval(params->u.dvbt.guard_interval, 0, dvbfe_dvbt_guard_interval_to_kapi);
383 		kparams.u.ofdm.hierarchy_information =
384 			lookupval(params->u.dvbt.hierarchy_information, 0, dvbfe_dvbt_hierarchy_to_kapi);
385                 break;
386 
387 	case FE_ATSC:
388 		kparams.u.vsb.modulation = lookupval(params->u.atsc.modulation, 0, dvbfe_atsc_mod_to_kapi);
389 		break;
390 
391 	default:
392 		return -EINVAL;
393 	}
394 
395 	// set it and check for error
396 	res = ioctl(fehandle->fd, FE_SET_FRONTEND, &kparams);
397 	if (res)
398 		return res;
399 
400 	// 0 => return immediately
401 	if (timeout == 0) {
402 		return 0;
403 	}
404 
405 	/* calculate timeout */
406 	if (timeout > 0) {
407 		gettimeofday(&endtime, NULL);
408 		timeout *= 1000;
409 		endtime.tv_sec += timeout / 1000000;
410 		endtime.tv_usec += timeout % 1000000;
411 	}
412 
413 	/* wait for a lock */
414 	while(1) {
415 		/* has it locked? */
416 		if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) {
417 			if (status & FE_HAS_LOCK) {
418 				break;
419 			}
420 		}
421 
422 		/* check for timeout */
423 		if (timeout > 0) {
424 			struct timeval curtime;
425 			gettimeofday(&curtime, NULL);
426 			if ((curtime.tv_sec > endtime.tv_sec) ||
427 			    ((curtime.tv_sec == endtime.tv_sec) && (curtime.tv_usec >= endtime.tv_usec))) {
428 				break;
429 			}
430 		}
431 
432 		/* delay for a bit */
433 		usleep(100000);
434 	}
435 
436 	/* exit */
437 	if (status & FE_HAS_LOCK)
438 		return 0;
439 	return -ETIMEDOUT;
440 }
441 
dvbfe_get_pollfd(struct dvbfe_handle * handle)442 int dvbfe_get_pollfd(struct dvbfe_handle *handle)
443 {
444 	return handle->fd;
445 }
446 
dvbfe_set_22k_tone(struct dvbfe_handle * fehandle,enum dvbfe_sec_tone_mode tone)447 int dvbfe_set_22k_tone(struct dvbfe_handle *fehandle, enum dvbfe_sec_tone_mode tone)
448 {
449 	int ret = 0;
450 
451 	switch (tone) {
452 	case DVBFE_SEC_TONE_OFF:
453 		ret = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF);
454 		break;
455 	case DVBFE_SEC_TONE_ON:
456 		ret = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON);
457 		break;
458 	default:
459 		print(verbose, ERROR, 1, "Invalid command !");
460 		break;
461 	}
462 	if (ret == -1)
463 		print(verbose, ERROR, 1, "IOCTL failed !");
464 
465 	return ret;
466 }
467 
dvbfe_set_tone_data_burst(struct dvbfe_handle * fehandle,enum dvbfe_sec_mini_cmd minicmd)468 int dvbfe_set_tone_data_burst(struct dvbfe_handle *fehandle, enum dvbfe_sec_mini_cmd minicmd)
469 {
470 	int ret = 0;
471 
472 	switch (minicmd) {
473 	case DVBFE_SEC_MINI_A:
474 		ret = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A);
475 		break;
476 	case DVBFE_SEC_MINI_B:
477 		ret = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B);
478 		break;
479 	default:
480 		print(verbose, ERROR, 1, "Invalid command");
481 		break;
482 	}
483 	if (ret == -1)
484 		print(verbose, ERROR, 1, "IOCTL failed");
485 
486 	return ret;
487 }
488 
dvbfe_set_voltage(struct dvbfe_handle * fehandle,enum dvbfe_sec_voltage voltage)489 int dvbfe_set_voltage(struct dvbfe_handle *fehandle, enum dvbfe_sec_voltage voltage)
490 {
491 	int ret = 0;
492 
493 	switch (voltage) {
494 	case DVBFE_SEC_VOLTAGE_OFF:
495 		ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF);
496 		break;
497 	case DVBFE_SEC_VOLTAGE_13:
498 		ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13);
499 		break;
500 	case DVBFE_SEC_VOLTAGE_18:
501 		ret = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18);
502 		break;
503 	default:
504 		print(verbose, ERROR, 1, "Invalid command");
505 		break;
506 	}
507 	if (ret == -1)
508 		print(verbose, ERROR, 1, "IOCTL failed");
509 
510 	return ret;
511 }
512 
dvbfe_set_high_lnb_voltage(struct dvbfe_handle * fehandle,int on)513 int dvbfe_set_high_lnb_voltage(struct dvbfe_handle *fehandle, int on)
514 {
515 	switch (on) {
516 	case 0:
517 		ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0);
518 		break;
519 	default:
520 		ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1);
521 		break;
522 	}
523 	return 0;
524 }
525 
dvbfe_do_dishnetworks_legacy_command(struct dvbfe_handle * fehandle,unsigned int cmd)526 int dvbfe_do_dishnetworks_legacy_command(struct dvbfe_handle *fehandle, unsigned int cmd)
527 {
528 	int ret = 0;
529 
530 	ret = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, cmd);
531 	if (ret == -1)
532 		print(verbose, ERROR, 1, "IOCTL failed");
533 
534 	return ret;
535 }
536 
dvbfe_do_diseqc_command(struct dvbfe_handle * fehandle,uint8_t * data,uint8_t len)537 int dvbfe_do_diseqc_command(struct dvbfe_handle *fehandle, uint8_t *data, uint8_t len)
538 {
539 	int ret = 0;
540 	struct dvb_diseqc_master_cmd diseqc_message;
541 
542 	if (len > 6)
543 		return -EINVAL;
544 
545 	diseqc_message.msg_len = len;
546 	memcpy(diseqc_message.msg, data, len);
547 
548 	ret = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &diseqc_message);
549 	if (ret == -1)
550 		print(verbose, ERROR, 1, "IOCTL failed");
551 
552 	return ret;
553 }
554 
dvbfe_diseqc_read(struct dvbfe_handle * fehandle,int timeout,unsigned char * buf,unsigned int len)555 int dvbfe_diseqc_read(struct dvbfe_handle *fehandle, int timeout, unsigned char *buf, unsigned int len)
556 {
557 	struct dvb_diseqc_slave_reply reply;
558 	int result;
559 
560 	if (len > 4)
561 		len = 4;
562 
563 	reply.timeout = timeout;
564 	reply.msg_len = len;
565 
566 	if ((result = ioctl(fehandle->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply)) != 0)
567 		return result;
568 
569 	if (reply.msg_len < len)
570 		len = reply.msg_len;
571 	memcpy(buf, reply.msg, len);
572 
573 	return len;
574 }
575