]> git.sesse.net Git - vlc/blobdiff - modules/access/dtv/linux.c
Revert "Add an automate variable to detect Android builb and use it to forbid build of"
[vlc] / modules / access / dtv / linux.c
index de98803a526c86e5ec06ba97f91f7ed2c8d17c04..16fbd1e82d18c65e18f8b9b8bf4bcb3fa203fc04 100644 (file)
@@ -32,6 +32,7 @@
 #include <poll.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <linux/dvb/version.h>
 #include <linux/dvb/frontend.h>
 #include <linux/dvb/dmx.h>
 
 # define O_SEARCH O_RDONLY
 #endif
 
+#define DVBv5(minor) \
+        (DVB_API_VERSION > 5 \
+     || (DVB_API_VERSION == 5 && DVB_API_VERSION_MINOR >= (minor)))
+#if !DVBv5(0)
+# error Linux DVB kernel headers version 2.6.28 or later required.
+#endif
+
 /** Opens the device directory for the specified DVB adapter */
 static int dvb_open_adapter (uint8_t adapter)
 {
@@ -132,24 +140,26 @@ static int dvb_parse_modulation (const char *str, int def)
     return dvb_parse_str (str, mods, sizeof (mods) / sizeof (*mods), def);
 }
 
-static int dvb_parse_fec (const char *str)
+static int dvb_parse_fec (uint32_t fec)
 {
-    static const dvb_str_map_t rates[] =
+    static const dvb_int_map_t rates[] =
     {
-        { "",     FEC_AUTO },
-        { "1/2",  FEC_1_2  },
+        { 0,             FEC_NONE },
+        { VLC_FEC(1,2),  FEC_1_2  },
         // TODO: 1/3
         // TODO: 1/4
-        { "2/3",  FEC_2_3  },
-        { "3/4",  FEC_3_4  },
-        { "4/5",  FEC_4_5  },
-        { "5/6",  FEC_5_6  },
-        { "6/7",  FEC_6_7  },
-        { "7/8",  FEC_7_8  },
-        { "8/9",  FEC_8_9  },
-        { "9/10", FEC_9_10 },
+        { VLC_FEC(2,3),  FEC_2_3  },
+        { VLC_FEC(3,4),  FEC_3_4  },
+        { VLC_FEC(3,5),  FEC_3_5  },
+        { VLC_FEC(4,5),  FEC_4_5  },
+        { VLC_FEC(5,6),  FEC_5_6  },
+        { VLC_FEC(6,7),  FEC_6_7  },
+        { VLC_FEC(7,8),  FEC_7_8  },
+        { VLC_FEC(8,9),  FEC_8_9  },
+        { VLC_FEC(9,10), FEC_9_10 },
+        { VLC_FEC_AUTO,  FEC_AUTO },
     };
-    return dvb_parse_str (str, rates, sizeof (rates) / sizeof (*rates),
+    return dvb_parse_int (fec, rates, sizeof (rates) / sizeof (*rates),
                           FEC_AUTO);
 }
 
@@ -271,6 +281,14 @@ dvb_device_t *dvb_open (vlc_object_t *obj, bool tune)
         msg_Dbg (obj, "using frontend: %s", d->info.name);
         msg_Dbg (obj, " type %u, capabilities 0x%08X", d->info.type,
                  d->info.caps);
+        msg_Dbg (obj, " frequencies %10"PRIu32" to %10"PRIu32,
+                 d->info.frequency_min, d->info.frequency_max);
+        msg_Dbg (obj, " (%"PRIu32" tolerance, %"PRIu32" per step)",
+                 d->info.frequency_tolerance, d->info.frequency_stepsize);
+        msg_Dbg (obj, " bauds rates %10"PRIu32" to %10"PRIu32,
+                 d->info.symbol_rate_min, d->info.symbol_rate_max);
+        msg_Dbg (obj, " (%"PRIu32" tolerance)",
+                 d->info.symbol_rate_tolerance);
 
         d->ca = dvb_open_node (dirfd, device, "ca", O_RDWR);
         if (d->ca == -1)
@@ -523,20 +541,165 @@ int dvb_tune (dvb_device_t *d)
 
 /*** DVB-C ***/
 int dvb_set_dvbc (dvb_device_t *d, uint32_t freq, const char *modstr,
-                  uint32_t srate, const char *fecstr)
+                  uint32_t srate, uint32_t fec)
 {
     unsigned mod = dvb_parse_modulation (modstr, QAM_AUTO);
-    unsigned fec = dvb_parse_fec (fecstr);
+    fec = dvb_parse_fec (fec);
 
-    return dvb_set_props (d, 5, DTV_CLEAR, 0,
+    return dvb_set_props (d, 6, DTV_CLEAR, 0,
                           DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_AC,
-                          DTV_FREQUENCY, freq, DTV_MODULATION, mod,
+                          DTV_FREQUENCY, freq * 1000, DTV_MODULATION, mod,
                           DTV_SYMBOL_RATE, srate, DTV_INNER_FEC, fec);
 }
 
 
 /*** DVB-S ***/
-/* TODO */
+static unsigned dvb_parse_polarization (char pol)
+{
+    static const dvb_int_map_t tab[5] = {
+        { 0,   SEC_VOLTAGE_OFF },
+        { 'H', SEC_VOLTAGE_18  },
+        { 'L', SEC_VOLTAGE_18  },
+        { 'R', SEC_VOLTAGE_13  },
+        { 'V', SEC_VOLTAGE_13  },
+    };
+    return dvb_parse_int (pol, tab, 5, SEC_VOLTAGE_OFF);
+}
+
+int dvb_set_sec (dvb_device_t *d, uint32_t freq, char pol,
+                 uint32_t lowf, uint32_t highf, uint32_t switchf)
+{
+    /* Always try to configure high voltage, but only warn on enable failure */
+    int val = var_InheritBool (d->obj, "dvb-high-voltage");
+    if (ioctl (d->frontend, FE_ENABLE_HIGH_LNB_VOLTAGE, &val) < 0 && val)
+        msg_Err (d->obj, "cannot enable high LNB voltage: %m");
+
+    /* Windows BDA exposes a higher-level API covering LNB oscillators.
+     * So lets pretend this is platform-specific stuff and do it here. */
+    if (!lowf)
+    {   /* Default oscillator frequencies */
+        static const struct
+        {
+             uint16_t min, max, low, high;
+        } tab[] =
+        {    /*  min    max    low   high */
+             { 10700, 13250,  9750, 10600 }, /* Ku band */
+             {  4500,  4800,  5950,     0 }, /* C band (high) */
+             {  3400,  4200,  5150,     0 }, /* C band (low) */
+             {  2500,  2700,  3650,     0 }, /* S band */
+             {   950,  2150,     0,     0 }, /* adjusted IF (L band) */
+        };
+        uint_fast16_t mhz = freq / 1000;
+
+        for (size_t i = 0; i < sizeof (tab) / sizeof (tab[0]); i++)
+             if (mhz >= tab[i].min && mhz <= tab[i].max)
+             {
+                 lowf = tab[i].low * 1000;
+                 highf = tab[i].high * 1000;
+                 goto known;
+             }
+
+        msg_Err (d->obj, "no known band for frequency %u kHz", freq);
+known:
+        msg_Dbg (d->obj, "selected LNB low: %u kHz, LNB high: %u kHz",
+                 lowf, highf);
+    }
+
+    /* Use high oscillator frequency? */
+    bool high = highf != 0 && freq > switchf;
+
+    freq -= high ? highf : lowf;
+    if ((int32_t)freq < 0)
+        freq *= -1;
+    assert (freq < 0x7fffffff);
+
+    int tone;
+    switch (var_InheritInteger (d->obj, "dvb-tone"))
+    {
+        case 0:  tone = SEC_TONE_OFF; break;
+        case 1:  tone = SEC_TONE_ON;  break;
+        default: tone = high ? SEC_TONE_ON : SEC_TONE_OFF;
+    }
+
+    /*** LNB selection / DiSEqC ***/
+    unsigned voltage = dvb_parse_polarization (pol);
+    if (dvb_set_props (d, 2, DTV_TONE, SEC_TONE_OFF, DTV_VOLTAGE, voltage))
+        return -1;
+
+    unsigned satno = var_InheritInteger (d->obj, "dvb-satno");
+    if (satno > 0)
+    {
+        /* DiSEqC 1.0 */
+#undef msleep /* we know what we are doing! */
+        struct dvb_diseqc_master_cmd cmd;
+
+        satno = (satno - 1) & 3;
+        cmd.msg[0] = 0xE0; /* framing: master, no reply, 1st TX */
+        cmd.msg[1] = 0x10; /* address: all LNB/switch */
+        cmd.msg[2] = 0x38; /* command: Write Port Group 0 */
+        cmd.msg[3] = 0xF0  /* data[0]: clear all bits */
+                   | (satno << 2) /* LNB (A, B, C or D) */
+                   | ((voltage == SEC_VOLTAGE_18) << 1) /* polarization */
+                   | (tone == SEC_TONE_ON); /* option */
+        cmd.msg[4] = cmd.msg[5] = 0; /* unused */
+        msleep (15000); /* wait 15 ms before DiSEqC command */
+        if (ioctl (d->frontend, FE_DISEQC_SEND_MASTER_CMD, &cmd) < 0)
+        {
+            msg_Err (d->obj, "cannot send DiSEqC command: %m");
+            return -1;
+        }
+        msleep (54000 + 15000);
+
+        /* Mini-DiSEqC */
+        satno &= 1;
+        if (ioctl (d->frontend, FE_DISEQC_SEND_BURST,
+                   satno ? SEC_MINI_B : SEC_MINI_A) < 0)
+        {
+            msg_Err (d->obj, "cannot send Mini-DiSEqC tone burst: %m");
+            return -1;
+        }
+        msleep (15000);
+    }
+
+    /* Continuous tone (to select high oscillator frequency) */
+    return dvb_set_props (d, 2, DTV_FREQUENCY, freq, DTV_TONE, tone);
+}
+
+int dvb_set_dvbs (dvb_device_t *d, uint32_t freq, uint32_t srate, uint32_t fec)
+{
+    fec = dvb_parse_fec (fec);
+
+    return dvb_set_props (d, 5, DTV_CLEAR, 0, DTV_DELIVERY_SYSTEM, SYS_DVBS,
+                          DTV_FREQUENCY, freq, DTV_SYMBOL_RATE, srate,
+                          DTV_INNER_FEC, fec);
+}
+
+int dvb_set_dvbs2 (dvb_device_t *d, uint32_t freq, const char *modstr,
+                   uint32_t srate, uint32_t fec, int pilot, int rolloff)
+{
+    unsigned mod = dvb_parse_modulation (modstr, QPSK);
+    fec = dvb_parse_fec (fec);
+
+    switch (pilot)
+    {
+        case 0:  pilot = PILOT_OFF;  break;
+        case 1:  pilot = PILOT_ON;   break;
+        default: pilot = PILOT_AUTO; break;
+    }
+
+    switch (rolloff)
+    {
+        case 20: rolloff = ROLLOFF_20;  break;
+        case 25: rolloff = ROLLOFF_25;  break;
+        case 35: rolloff = ROLLOFF_35;  break;
+        default: rolloff = PILOT_AUTO; break;
+    }
+
+    return dvb_set_props (d, 8, DTV_CLEAR, 0, DTV_DELIVERY_SYSTEM, SYS_DVBS2,
+                          DTV_FREQUENCY, freq, DTV_MODULATION, mod,
+                          DTV_SYMBOL_RATE, srate, DTV_INNER_FEC, fec,
+                          DTV_PILOT, pilot, DTV_ROLLOFF, rolloff);
+}
 
 
 /*** DVB-T ***/
@@ -545,7 +708,9 @@ static int dvb_parse_transmit_mode (int i)
     static const dvb_int_map_t tab[] = {
         { -1, TRANSMISSION_MODE_AUTO },
         {  2, TRANSMISSION_MODE_2K   },
+#if DVBv5(1)
         {  4, TRANSMISSION_MODE_4K   },
+#endif
         {  8, TRANSMISSION_MODE_8K   },
 #if 0
         { 16, TRANSMISSION_MODE_16K  },
@@ -556,19 +721,19 @@ static int dvb_parse_transmit_mode (int i)
                           TRANSMISSION_MODE_AUTO);
 }
 
-static int dvb_parse_guard (const char *str)
+static int dvb_parse_guard (uint32_t guard)
 {
-    static const dvb_str_map_t tab[] = {
-        { "",       GUARD_INTERVAL_AUTO },
-      /*{ "1/128",  GUARD_INTERVAL_1_128 },*/
-        { "1/16",   GUARD_INTERVAL_1_16 },
-        { "1/32",   GUARD_INTERVAL_1_32 },
-        { "1/4",    GUARD_INTERVAL_1_4 },
-        { "1/8",    GUARD_INTERVAL_1_8 },
-      /*{ "19/128", GUARD_INTERVAL_19_128 },*/
-      /*{ "9/256",  GUARD_INTERVAL_9_256 },*/
+    static const dvb_int_map_t tab[] = {
+      /*{ VLC_GUARD(1,128),  GUARD_INTERVAL_1_128 },*/
+        { VLC_GUARD(1,16),   GUARD_INTERVAL_1_16 },
+        { VLC_GUARD(1,32),   GUARD_INTERVAL_1_32 },
+        { VLC_GUARD(1,4),    GUARD_INTERVAL_1_4 },
+        { VLC_GUARD(1,8),    GUARD_INTERVAL_1_8 },
+      /*{ VLC_GUARD(19,128), GUARD_INTERVAL_19_128 },*/
+      /*{ VLC_GUARD(9,256),  GUARD_INTERVAL_9_256 },*/
+        { VLC_GUARD_AUTO,    GUARD_INTERVAL_AUTO },
     };
-    return dvb_parse_str (str, tab, sizeof (tab) / sizeof (*tab),
+    return dvb_parse_int (guard, tab, sizeof (tab) / sizeof (*tab),
                           GUARD_INTERVAL_AUTO);
 }
 
@@ -586,23 +751,23 @@ static int dvb_parse_hierarchy (int i)
 }
 
 int dvb_set_dvbt (dvb_device_t *d, uint32_t freq, const char *modstr,
-                  const char *fechstr, const char *feclstr, uint32_t bandwidth,
-                  int transmit_val, const char *guardstr, int hierarchy_val)
+                  uint32_t fec_hp, uint32_t fec_lp, uint32_t bandwidth,
+                  int transmit_mode, uint32_t guard, int hierarchy)
 {
     uint32_t mod = dvb_parse_modulation (modstr, QAM_AUTO);
-    uint32_t fec_hp = dvb_parse_fec (fechstr);
-    uint32_t fec_lp = dvb_parse_fec (feclstr);
+    fec_hp = dvb_parse_fec (fec_hp);
+    fec_lp = dvb_parse_fec (fec_lp);
     bandwidth *= 1000000;
-    uint32_t transmit_mode = dvb_parse_transmit_mode (transmit_val);
-    uint32_t guard_it = dvb_parse_guard (guardstr);
-    uint32_t hierarchy = dvb_parse_hierarchy (hierarchy_val);
+    transmit_mode = dvb_parse_transmit_mode (transmit_mode);
+    guard = dvb_parse_guard (guard);
+    hierarchy = dvb_parse_hierarchy (hierarchy);
 
     return dvb_set_props (d, 10, DTV_CLEAR, 0, DTV_DELIVERY_SYSTEM, SYS_DVBT,
-                          DTV_FREQUENCY, freq, DTV_MODULATION, mod,
+                          DTV_FREQUENCY, freq * 1000, DTV_MODULATION, mod,
                           DTV_CODE_RATE_HP, fec_hp, DTV_CODE_RATE_LP, fec_lp,
                           DTV_BANDWIDTH_HZ, bandwidth,
                           DTV_TRANSMISSION_MODE, transmit_mode,
-                          DTV_GUARD_INTERVAL, guard_it,
+                          DTV_GUARD_INTERVAL, guard,
                           DTV_HIERARCHY, hierarchy);
 }
 
@@ -613,5 +778,14 @@ int dvb_set_atsc (dvb_device_t *d, uint32_t freq, const char *modstr)
     unsigned mod = dvb_parse_modulation (modstr, VSB_8);
 
     return dvb_set_props (d, 4, DTV_CLEAR, 0, DTV_DELIVERY_SYSTEM, SYS_ATSC,
-                          DTV_FREQUENCY, freq, DTV_MODULATION, mod);
+                          DTV_FREQUENCY, freq * 1000, DTV_MODULATION, mod);
+}
+
+int dvb_set_cqam (dvb_device_t *d, uint32_t freq, const char *modstr)
+{
+    unsigned mod = dvb_parse_modulation (modstr, QAM_AUTO);
+
+    return dvb_set_props (d, 4, DTV_CLEAR, 0,
+                          DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_B,
+                          DTV_FREQUENCY, freq * 1000, DTV_MODULATION, mod);
 }