summaryrefslogtreecommitdiffstats
path: root/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c
diff options
context:
space:
mode:
Diffstat (limited to 'kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c')
-rw-r--r--kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c760
1 files changed, 760 insertions, 0 deletions
diff --git a/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c
new file mode 100644
index 0000000..fc6ecf4
--- /dev/null
+++ b/kaffeine/src/input/dvb/lib/libdvbapi/dvbfe.c
@@ -0,0 +1,760 @@
+/*
+ * libdvbfe - a DVB frontend library
+ *
+ * Copyright (C) 2005 Andrew de Quincey (adq_dvb@lidskialf.net)
+ * Copyright (C) 2005 Kenneth Aafloy (kenneth@linuxtv.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <errno.h>
+#include <linux/dvb/frontend.h>
+#include "dvbfe.h"
+
+#define GET_INFO_MIN_DELAY_US 100000
+
+static int dvbfe_spectral_inversion_to_kapi[][2] =
+{
+ { DVBFE_INVERSION_OFF, INVERSION_OFF },
+ { DVBFE_INVERSION_ON, INVERSION_ON },
+ { DVBFE_INVERSION_AUTO, INVERSION_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_code_rate_to_kapi[][2] =
+{
+ { DVBFE_FEC_NONE, FEC_NONE },
+ { DVBFE_FEC_1_2, FEC_1_2 },
+ { DVBFE_FEC_2_3, FEC_2_3 },
+ { DVBFE_FEC_3_4, FEC_3_4 },
+ { DVBFE_FEC_4_5, FEC_4_5 },
+ { DVBFE_FEC_5_6, FEC_5_6 },
+ { DVBFE_FEC_6_7, FEC_6_7 },
+ { DVBFE_FEC_7_8, FEC_7_8 },
+ { DVBFE_FEC_8_9, FEC_8_9 },
+ { DVBFE_FEC_AUTO, FEC_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_const_to_kapi[][2] =
+{
+ { DVBFE_DVBT_CONST_QPSK, FE_QPSK },
+ { DVBFE_DVBT_CONST_QAM_16, QAM_16 },
+ { DVBFE_DVBT_CONST_QAM_32, QAM_32 },
+ { DVBFE_DVBT_CONST_QAM_64, QAM_64 },
+ { DVBFE_DVBT_CONST_QAM_128, QAM_128 },
+ { DVBFE_DVBT_CONST_QAM_256, QAM_256 },
+ { DVBFE_DVBT_CONST_AUTO, QAM_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbc_mod_to_kapi[][2] =
+{
+ { DVBFE_DVBC_MOD_QAM_16, QAM_16 },
+ { DVBFE_DVBC_MOD_QAM_32, QAM_32 },
+ { DVBFE_DVBC_MOD_QAM_64, QAM_64 },
+ { DVBFE_DVBC_MOD_QAM_128, QAM_128 },
+ { DVBFE_DVBC_MOD_QAM_256, QAM_256 },
+ { DVBFE_DVBC_MOD_AUTO, QAM_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_atsc_mod_to_kapi[][2] =
+{
+ { DVBFE_ATSC_MOD_QAM_64, QAM_64 },
+ { DVBFE_ATSC_MOD_QAM_256, QAM_256 },
+ { DVBFE_ATSC_MOD_VSB_8, VSB_8 },
+ { DVBFE_ATSC_MOD_VSB_16, VSB_16 },
+ { DVBFE_ATSC_MOD_AUTO, QAM_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_transmit_mode_to_kapi[][2] =
+{
+ { DVBFE_DVBT_TRANSMISSION_MODE_2K, TRANSMISSION_MODE_2K },
+ { DVBFE_DVBT_TRANSMISSION_MODE_8K, TRANSMISSION_MODE_8K },
+ { DVBFE_DVBT_TRANSMISSION_MODE_AUTO, TRANSMISSION_MODE_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_bandwidth_to_kapi[][2] =
+{
+ { DVBFE_DVBT_BANDWIDTH_8_MHZ, BANDWIDTH_8_MHZ },
+ { DVBFE_DVBT_BANDWIDTH_7_MHZ, BANDWIDTH_7_MHZ },
+ { DVBFE_DVBT_BANDWIDTH_6_MHZ, BANDWIDTH_6_MHZ },
+ { DVBFE_DVBT_BANDWIDTH_AUTO, BANDWIDTH_AUTO },
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_guard_interval_to_kapi[][2] =
+{
+ { DVBFE_DVBT_GUARD_INTERVAL_1_32, GUARD_INTERVAL_1_32},
+ { DVBFE_DVBT_GUARD_INTERVAL_1_16, GUARD_INTERVAL_1_16},
+ { DVBFE_DVBT_GUARD_INTERVAL_1_8, GUARD_INTERVAL_1_8},
+ { DVBFE_DVBT_GUARD_INTERVAL_1_4, GUARD_INTERVAL_1_4},
+ { DVBFE_DVBT_GUARD_INTERVAL_AUTO, GUARD_INTERVAL_AUTO},
+ { -1, -1 }
+};
+
+static int dvbfe_dvbt_hierarchy_to_kapi[][2] =
+{
+ { DVBFE_DVBT_HIERARCHY_NONE, HIERARCHY_NONE },
+ { DVBFE_DVBT_HIERARCHY_1, HIERARCHY_1 },
+ { DVBFE_DVBT_HIERARCHY_2, HIERARCHY_2 },
+ { DVBFE_DVBT_HIERARCHY_4, HIERARCHY_4 },
+ { DVBFE_DVBT_HIERARCHY_AUTO, HIERARCHY_AUTO },
+ { -1, -1 }
+};
+
+static int lookupval(int val, int reverse, int table[][2])
+{
+ int i =0;
+
+ while(table[i][0] != -1) {
+ if (!reverse) {
+ if (val == table[i][0]) {
+ return table[i][1];
+ }
+ } else {
+ if (val == table[i][1]) {
+ return table[i][0];
+ }
+ }
+ i++;
+ }
+
+ return -1;
+}
+
+
+struct dvbfe_handle_prv {
+ int fd;
+ dvbfe_type_t type;
+ char *name;
+ struct timeval nextinfotime;
+ struct dvbfe_info cachedinfo;
+ int cachedreturnval;
+};
+
+dvbfe_handle_t dvbfe_open(int adapter, int frontend, int readonly)
+{
+ char filename[PATH_MAX+1];
+ struct dvbfe_handle_prv *fehandle;
+ int fd;
+ struct dvb_frontend_info info;
+
+ // flags
+ int flags = O_RDWR;
+ if (readonly) {
+ flags = O_RDONLY;
+ }
+
+ // open it (try normal /dev structure first)
+ sprintf(filename, "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
+ if ((fd = open(filename, flags)) < 0) {
+ // if that failed, try a flat /dev structure
+ sprintf(filename, "/dev/dvb%i.frontend%i", adapter, frontend);
+ if ((fd = open(filename, flags)) < 0) {
+ return NULL;
+ }
+ }
+
+ // determine fe type
+ if (ioctl(fd, FE_GET_INFO, &info)) {
+ close(fd);
+ return NULL;
+ }
+
+ // setup structure
+ fehandle = (struct dvbfe_handle_prv*) malloc(sizeof(struct dvbfe_handle_prv));
+ memset(fehandle, 0, sizeof(struct dvbfe_handle_prv));
+ fehandle->fd = fd;
+ switch(info.type) {
+ case FE_QPSK:
+ fehandle->type = DVBFE_TYPE_DVBS;
+ break;
+
+ case FE_QAM:
+ fehandle->type = DVBFE_TYPE_DVBC;
+ break;
+
+ case FE_OFDM:
+ fehandle->type = DVBFE_TYPE_DVBT;
+ break;
+
+ case FE_ATSC:
+ fehandle->type = DVBFE_TYPE_ATSC;
+ break;
+ }
+ fehandle->name = strndup(info.name, sizeof(info.name));
+
+ // done
+ return fehandle;
+}
+
+void dvbfe_close(dvbfe_handle_t _fehandle)
+{
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+
+ close(fehandle->fd);
+ free(fehandle->name);
+ free(fehandle);
+}
+
+int dvbfe_get_info(dvbfe_handle_t _fehandle, dvbfe_info_mask_t querymask, struct dvbfe_info *result)
+{
+ int returnval = 0;
+ fe_status_t status;
+ struct dvb_frontend_parameters kparams;
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+ struct timeval curtime;
+
+ // limit how often this is called to reduce bus traffic
+ gettimeofday(&curtime, NULL);
+ if ((curtime.tv_sec < fehandle->nextinfotime.tv_sec) ||
+ ((curtime.tv_sec == fehandle->nextinfotime.tv_sec) && (curtime.tv_usec < fehandle->nextinfotime.tv_usec))) {
+ memcpy(result, &fehandle->cachedinfo, sizeof(struct dvbfe_info));
+ return fehandle->cachedreturnval;
+ }
+
+ // retrieve the requested values
+ memset(result, 0, sizeof(result));
+ result->type = fehandle->type;
+ result->name = fehandle->name;
+ if (querymask & DVBFE_INFO_LOCKSTATUS) {
+ if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) {
+ returnval |= DVBFE_INFO_LOCKSTATUS;
+ if (status & FE_HAS_SIGNAL)
+ result->signal = 1;
+
+ if (status & FE_HAS_CARRIER)
+ result->carrier = 1;
+
+ if (status & FE_HAS_VITERBI)
+ result->viterbi = 1;
+
+ if (status & FE_HAS_SYNC)
+ result->sync = 1;
+
+ if (status & FE_HAS_LOCK)
+ result->lock = 1;
+ }
+ }
+ if (querymask & DVBFE_INFO_FEPARAMS) {
+ if (!ioctl(fehandle->fd, FE_GET_FRONTEND, &kparams)) {
+ returnval |= DVBFE_INFO_FEPARAMS;
+ result->feparams.frequency = kparams.frequency;
+ result->feparams.inversion = lookupval(kparams.inversion, 1, dvbfe_spectral_inversion_to_kapi);
+ switch(fehandle->type) {
+ case FE_QPSK:
+ result->feparams.u.dvbs.symbol_rate = kparams.u.qpsk.symbol_rate;
+ result->feparams.u.dvbs.fec_inner =
+ lookupval(kparams.u.qpsk.fec_inner, 1, dvbfe_code_rate_to_kapi);
+ break;
+
+ case FE_QAM:
+ result->feparams.u.dvbc.symbol_rate = kparams.u.qam.symbol_rate;
+ result->feparams.u.dvbc.fec_inner =
+ lookupval(kparams.u.qam.fec_inner, 1, dvbfe_code_rate_to_kapi);
+ result->feparams.u.dvbc.modulation =
+ lookupval(kparams.u.qam.modulation, 1, dvbfe_dvbc_mod_to_kapi);
+ break;
+
+ case FE_OFDM:
+ result->feparams.u.dvbt.bandwidth =
+ lookupval(kparams.u.ofdm.bandwidth, 1, dvbfe_dvbt_bandwidth_to_kapi);
+ result->feparams.u.dvbt.code_rate_HP =
+ lookupval(kparams.u.ofdm.code_rate_HP, 1, dvbfe_code_rate_to_kapi);
+ result->feparams.u.dvbt.code_rate_LP =
+ lookupval(kparams.u.ofdm.code_rate_LP, 1, dvbfe_code_rate_to_kapi);
+ result->feparams.u.dvbt.constellation =
+ lookupval(kparams.u.ofdm.constellation, 1, dvbfe_dvbt_const_to_kapi);
+ result->feparams.u.dvbt.transmission_mode =
+ lookupval(kparams.u.ofdm.transmission_mode, 1, dvbfe_dvbt_transmit_mode_to_kapi);
+ result->feparams.u.dvbt.guard_interval =
+ lookupval(kparams.u.ofdm.guard_interval, 1, dvbfe_dvbt_guard_interval_to_kapi);
+ result->feparams.u.dvbt.hierarchy_information =
+ lookupval(kparams.u.ofdm.hierarchy_information, 1, dvbfe_dvbt_hierarchy_to_kapi);
+ break;
+
+ case FE_ATSC:
+ result->feparams.u.atsc.modulation =
+ lookupval(kparams.u.vsb.modulation, 1, dvbfe_atsc_mod_to_kapi);
+ break;
+ }
+ }
+
+ }
+ if (querymask & DVBFE_INFO_BER) {
+ if (!ioctl(fehandle->fd, FE_READ_BER, &result->ber))
+ returnval |= DVBFE_INFO_BER;
+ }
+ if (querymask & DVBFE_INFO_SIGNAL_STRENGTH) {
+ if (!ioctl(fehandle->fd, FE_READ_SIGNAL_STRENGTH, &result->signal_strength))
+ returnval |= DVBFE_INFO_SIGNAL_STRENGTH;
+ }
+ if (querymask & DVBFE_INFO_SNR) {
+ if (!ioctl(fehandle->fd, FE_READ_SNR, &result->snr))
+ returnval |= DVBFE_INFO_SNR;
+ }
+ if (querymask & DVBFE_INFO_UNCORRECTED_BLOCKS) {
+ if (!ioctl(fehandle->fd, FE_READ_UNCORRECTED_BLOCKS, &result->ucblocks))
+ returnval |= DVBFE_INFO_UNCORRECTED_BLOCKS;
+ }
+
+ // setup for next poll
+ gettimeofday(&fehandle->nextinfotime, NULL);
+ fehandle->nextinfotime.tv_usec += GET_INFO_MIN_DELAY_US;
+ if (fehandle->nextinfotime.tv_usec >= 1000000) {
+ fehandle->nextinfotime.tv_usec -= 1000000;
+ fehandle->nextinfotime.tv_sec++;
+ }
+ memcpy(&fehandle->cachedinfo, result, sizeof(struct dvbfe_info));
+ fehandle->cachedreturnval = returnval;
+
+ // done
+ return returnval;
+}
+
+int dvbfe_set(dvbfe_handle_t _fehandle, struct dvbfe_parameters *params, int timeout)
+{
+ struct dvb_frontend_parameters kparams;
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+ int res;
+ struct timeval endtime;
+ fe_status_t status;
+
+ kparams.frequency = params->frequency;
+ kparams.inversion = lookupval(params->inversion, 0, dvbfe_spectral_inversion_to_kapi);
+ switch(fehandle->type) {
+ case FE_QPSK:
+ kparams.u.qpsk.symbol_rate = params->u.dvbs.symbol_rate;
+ kparams.u.qpsk.fec_inner = lookupval(params->u.dvbs.fec_inner, 0, dvbfe_code_rate_to_kapi);
+ break;
+
+ case FE_QAM:
+ kparams.u.qam.symbol_rate = params->u.dvbc.symbol_rate;
+ kparams.u.qam.fec_inner = lookupval(params->u.dvbc.fec_inner, 0, dvbfe_code_rate_to_kapi);
+ kparams.u.qam.modulation = lookupval(params->u.dvbc.modulation, 0, dvbfe_dvbc_mod_to_kapi);
+ break;
+
+ case FE_OFDM:
+ kparams.u.ofdm.bandwidth = lookupval(params->u.dvbt.bandwidth, 0, dvbfe_dvbt_bandwidth_to_kapi);
+ kparams.u.ofdm.code_rate_HP = lookupval(params->u.dvbt.code_rate_HP, 0, dvbfe_code_rate_to_kapi);
+ kparams.u.ofdm.code_rate_LP = lookupval(params->u.dvbt.code_rate_LP, 0, dvbfe_code_rate_to_kapi);
+ kparams.u.ofdm.constellation = lookupval(params->u.dvbt.constellation, 0, dvbfe_dvbt_const_to_kapi);
+ kparams.u.ofdm.transmission_mode =
+ lookupval(params->u.dvbt.transmission_mode, 0, dvbfe_dvbt_transmit_mode_to_kapi);
+ kparams.u.ofdm.guard_interval =
+ lookupval(params->u.dvbt.guard_interval, 0, dvbfe_dvbt_guard_interval_to_kapi);
+ kparams.u.ofdm.hierarchy_information =
+ lookupval(params->u.dvbt.hierarchy_information, 0, dvbfe_dvbt_hierarchy_to_kapi);
+ break;
+
+ case FE_ATSC:
+ kparams.u.vsb.modulation = lookupval(params->u.atsc.modulation, 0, dvbfe_atsc_mod_to_kapi);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ // set it and check for error
+ res = ioctl(fehandle->fd, FE_SET_FRONTEND, &kparams);
+ if (res)
+ return res;
+
+ // 0 => return immediately
+ if (timeout == 0) {
+ return 0;
+ }
+
+ /* calculate timeout */
+ if (timeout > 0) {
+ gettimeofday(&endtime, NULL);
+ timeout *= 1000;
+ endtime.tv_sec += timeout / 1000000;
+ endtime.tv_usec += timeout % 1000000;
+ }
+
+ /* wait for a lock */
+ while(1) {
+ /* has it locked? */
+ if (!ioctl(fehandle->fd, FE_READ_STATUS, &status)) {
+ if (status & FE_HAS_LOCK) {
+ break;
+ }
+ }
+
+ /* check for timeout */
+ if (timeout > 0) {
+ struct timeval curtime;
+ gettimeofday(&curtime, NULL);
+ if ((curtime.tv_sec > endtime.tv_sec) ||
+ ((curtime.tv_sec == endtime.tv_sec) && (curtime.tv_usec >= endtime.tv_usec))) {
+ break;
+ }
+ }
+
+ /* delay for a bit */
+ usleep(100000);
+ }
+
+ /* exit */
+ if (status & FE_HAS_LOCK)
+ return 0;
+ return -ETIMEDOUT;
+}
+
+void dvbfe_poll(dvbfe_handle_t fehandle)
+{
+ // no implementation required yet
+}
+
+
+
+
+
+
+
+int dvbfe_diseqc_command(dvbfe_handle_t _fehandle, char *command)
+{
+ int i = 0;
+ int waittime;
+ int status;
+ struct dvb_diseqc_master_cmd master_cmd;
+ unsigned int tmpcmd[6];
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+ char value_s[20];
+ int value_i;
+ int addr;
+
+ while(command[i]) {
+ /* kill whitespace */
+ if (isspace(command[i])) {
+ i++;
+ continue;
+ }
+
+ switch(command[i]) {
+ case 't':
+ if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_OFF)) != 0)
+ return status;
+ break;
+
+ case 'T':
+ if ((status = ioctl(fehandle->fd, FE_SET_TONE, SEC_TONE_ON)) != 0)
+ return status;
+ break;
+
+ case '_':
+ if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_OFF)) != 0)
+ return status;
+ break;
+
+ case 'v':
+ if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13)) != 0)
+ return status;
+ break;
+
+ case 'V':
+ if ((status = ioctl(fehandle->fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18)) != 0)
+ return status;
+ break;
+
+ case 'A':
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_A)) != 0)
+ return status;
+ break;
+
+ case 'B':
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_BURST, SEC_MINI_B)) != 0)
+ return status;
+ break;
+
+ case '+':
+ ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 1);
+ /* don't care if this one is not supported */
+ break;
+
+ case '-':
+ ioctl(fehandle->fd, FE_ENABLE_HIGH_LNB_VOLTAGE, 0);
+ /* don't care if this one is not supported */
+ break;
+
+ case 'W':
+ waittime = atoi(command + i + 1);
+ if (waittime == 0) {
+ return -EINVAL;
+ }
+ usleep(waittime * 1000);
+ while(command[i] && !isspace(command[i]))
+ i++;
+ break;
+
+ case '.': // extended command
+ {
+ i++;
+
+ if (!strncmp(command+i, "D(", 2)) {
+ i += 2;
+
+ master_cmd.msg_len =
+ sscanf(command+i, "%x %x %x %x %x %x",
+ tmpcmd, tmpcmd+1, tmpcmd+2, tmpcmd+3, tmpcmd+4, tmpcmd+5);
+ if (master_cmd.msg_len == 0)
+ return -EINVAL;
+ master_cmd.msg[0] = tmpcmd[0];
+ master_cmd.msg[1] = tmpcmd[1];
+ master_cmd.msg[2] = tmpcmd[2];
+ master_cmd.msg[3] = tmpcmd[3];
+ master_cmd.msg[4] = tmpcmd[4];
+ master_cmd.msg[5] = tmpcmd[5];
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+ } else if (!strncmp(command+i, "Dband(", 6)) {
+ if (sscanf(command+i+6, "%i %2s", &addr, value_s) != 2)
+ return -EINVAL;
+ if (!strncmp(value_s, "lo", 2)) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x20;
+ master_cmd.msg_len = 3;
+ } else if (!strncmp(value_s, "hi", 2)) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x24;
+ master_cmd.msg_len = 3;
+ } else {
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if ((!strncmp(command+i, "Dpolarisation(", 14) ||
+ (!strncmp(command+i, "Dpolarization(", 14)))) {
+ if (sscanf(command+i+14, "%i %1s", &addr, value_s) != 2)
+ return -EINVAL;
+ switch(*value_s) {
+ case 'H':
+ case 'L':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x25;
+ master_cmd.msg_len = 3;
+ break;
+
+ case 'V':
+ case 'R':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x21;
+ master_cmd.msg_len = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dsatellite_position(", 20)) {
+ if (sscanf(command+i+20, "%i %1s", &addr, value_s) != 2)
+ return -EINVAL;
+ switch(*value_s) {
+ case 'A':
+ case 'C':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x22;
+ master_cmd.msg_len = 3;
+ break;
+
+ case 'B':
+ case 'D':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x26;
+ master_cmd.msg_len = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dswitch_option(", 15)) {
+ if (sscanf(command+i+15, "%i %1s", &addr, value_s) != 2)
+ return -EINVAL;
+ switch(*value_s) {
+ case 'A':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x23;
+ master_cmd.msg_len = 3;
+ break;
+
+ case 'B':
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x27;
+ master_cmd.msg_len = 3;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dport_pins(", 11)) {
+ int mask;
+ if (sscanf(command+i+11, "%i %i %i", &addr, &mask, &value_i) != 3)
+ return -EINVAL;
+
+ if (mask & 0x0f) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x38;
+ master_cmd.msg[3] = ((mask & 0x0f) << 4) | (value_i & 0x0f);
+ master_cmd.msg_len = 4;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+ }
+ if (mask & 0xf0) {
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x39;
+ master_cmd.msg[3] = (mask & 0xf0) | ((value_i & 0xf0) >> 4);
+ master_cmd.msg_len = 4;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+ }
+
+ } else if (!strncmp(command+i, "Dgoto_preset(", 13)) {
+ if (sscanf(command+i+13, "%i %i", &addr, &value_i) != 2)
+ return -EINVAL;
+
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x3b;
+ master_cmd.msg[3] = value_i;
+ master_cmd.msg_len = 4;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "Dgoto_angle(", 12)) {
+ int integer = 0;
+ int fraction = 0;
+ char *tmp;
+
+ if (sscanf(command+i+12, "%i %s", &addr, value_s) != 2)
+ return -EINVAL;
+
+ // parse the integer and fractional parts using fixed point
+ integer = atoi(value_s);
+ tmp = strchr(value_s, '.');
+ if (tmp != NULL) {
+ tmp++;
+ tmp[3] = 0;
+ fraction = ((atoi(tmp) * 16000) / 1000000) & 0xf;
+ }
+
+ // generate the command
+ master_cmd.msg[0] = 0xe0;
+ master_cmd.msg[1] = addr;
+ master_cmd.msg[2] = 0x6e;
+ if (integer < -256) {
+ return -EINVAL;
+ } else if (integer < 0) {
+ integer = -integer;
+ master_cmd.msg[3] = 0xf0;
+ } else if (integer < 256) {
+ master_cmd.msg[3] = 0x00;
+ } else if (integer < 512) {
+ integer -= 256;
+ master_cmd.msg[3] = 0x10;
+ } else {
+ return -EINVAL;
+ }
+ master_cmd.msg[3] |= ((integer / 16) & 0x0f);
+ integer = integer % 16;
+ master_cmd.msg[4] |= ((integer & 0x0f) << 4) | fraction;
+ master_cmd.msg_len = 5;
+
+ if ((status = ioctl(fehandle->fd, FE_DISEQC_SEND_MASTER_CMD, &master_cmd)) != 0)
+ return status;
+
+ } else if (!strncmp(command+i, "dishnetworks(", 13)) {
+ if (sscanf(command+i+13, "%i", tmpcmd) != 1)
+ return -EINVAL;
+
+ if ((status = ioctl(fehandle->fd, FE_DISHNETWORK_SEND_LEGACY_CMD, tmpcmd)) != 0)
+ return status;
+ }
+
+ /* skip to the end... */
+ while(command[i] && (command[i] != ')'))
+ i++;
+ break;
+ }
+
+
+ default:
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+int dvbfe_diseqc_read(dvbfe_handle_t _fehandle, int timeout, unsigned char *buf, unsigned int len)
+{
+ struct dvb_diseqc_slave_reply reply;
+ int result;
+ struct dvbfe_handle_prv *fehandle = (struct dvbfe_handle_prv*) _fehandle;
+
+ if (len > 4)
+ len = 4;
+
+ reply.timeout = timeout;
+ reply.msg_len = len;
+
+ if ((result = ioctl(fehandle->fd, FE_DISEQC_RECV_SLAVE_REPLY, reply)) != 0)
+ return result;
+
+ if (reply.msg_len < len)
+ len = reply.msg_len;
+ memcpy(buf, reply.msg, len);
+
+ return len;
+}