return -1;
}
-const delsys_t *dvb_guess_system (dvb_device_t *d)
+/**
+ * Detects supported delivery systems.
+ * @return a bit mask of supported systems (zero on failure)
+ */
+unsigned dvb_enum_systems (dvb_device_t *d)
{
- if (d->frontend == -1)
+ unsigned systems = 0;
+
+ for (unsigned n = 0; n < 256; n++)
{
- d->frontend = dvb_open_node (d->dir, "frontend", 0, O_RDWR);
- if (d->frontend == -1)
+ int fd = dvb_open_node (d->dir, "frontend", n, O_RDWR);
+ if (fd == -1)
{
- msg_Err (d->obj, "cannot access frontend %u; %m", 0);
- return NULL;
+ if (errno == ENOENT)
+ break; /* all frontends already enumerated */
+ msg_Err (d->obj, "cannot access frontend %u; %m", n);
+ continue;
}
- if (ioctl (d->frontend, FE_GET_INFO, &d->info) < 0)
+ struct dvb_frontend_info info;
+ if (ioctl (fd, FE_GET_INFO, &info) < 0)
{
- msg_Err (d->obj, "cannot get frontend %u info: %m", 0);
- close (d->frontend);
- d->frontend = -1;
- return NULL;
+ msg_Err (d->obj, "cannot get frontend %u info: %m", n);
+ close (fd);
+ continue;
}
- }
+ close (fd);
- //bool v2 = d->info.caps & FE_CAN_2G_MODULATION;
- switch (d->info.type)
- {
- case FE_QPSK: return /*v2 ? &dvbs2 :*/ &dvbs;
- case FE_QAM: return &dvbc;
- case FE_OFDM: return /*v2 ? &dvbt2 :*/ &dvbt;
- case FE_ATSC: return &atsc;
+ /* Linux DVB lacks detection for non-DVB/non-ATSC demods */
+ static const unsigned types[] = {
+ [FE_QPSK] = DVB_S,
+ [FE_QAM] = DVB_C,
+ [FE_OFDM] = DVB_T,
+ [FE_ATSC] = ATSC,
+ };
+
+ if (((unsigned)info.type) >= sizeof (types) / sizeof (types[0]))
+ {
+ msg_Err (d->obj, "unknown frontend type %u", info.type);
+ continue;
+ }
+
+ unsigned sys = types[info.type];
+ if (info.caps & FE_CAN_2G_MODULATION)
+ sys |= sys << 1; /* DVB_foo -> DVB_foo|DVB_foo2 */
+ systems |= sys;
}
- return NULL;
+ return systems;
}
float dvb_get_signal_strength (dvb_device_t *d)
return -1;
return dvb_set_props (d, 6, DTV_CLEAR, 0,
DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_AC,
- DTV_FREQUENCY, freq * 1000, DTV_MODULATION, mod,
+ DTV_FREQUENCY, freq, DTV_MODULATION, mod,
DTV_SYMBOL_RATE, srate, DTV_INNER_FEC, fec);
}
return dvb_parse_int (pol, tab, 5, SEC_VOLTAGE_OFF);
}
-int dvb_set_sec (dvb_device_t *d, uint32_t freq, char pol,
+int dvb_set_sec (dvb_device_t *d, uint64_t freq_Hz, char pol,
uint32_t lowf, uint32_t highf, uint32_t switchf)
{
+ uint32_t freq = freq_Hz / 1000;
+
/* 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)
{ 2500, 2700, 3650, 0 }, /* S band */
{ 950, 2150, 0, 0 }, /* adjusted IF (L band) */
};
- uint_fast16_t mhz = freq / 1000;
+ 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)
+ if (mHz >= tab[i].min && mHz <= tab[i].max)
{
lowf = tab[i].low * 1000;
highf = tab[i].high * 1000;
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)
+int dvb_set_dvbs (dvb_device_t *d, uint64_t freq_Hz,
+ uint32_t srate, uint32_t fec)
{
+ uint32_t freq = freq_Hz / 1000;
fec = dvb_parse_fec (fec);
if (dvb_find_frontend (d, FE_QPSK, FE_IS_STUPID))
DTV_INNER_FEC, fec);
}
-int dvb_set_dvbs2 (dvb_device_t *d, uint32_t freq, const char *modstr,
+int dvb_set_dvbs2 (dvb_device_t *d, uint64_t freq_Hz, const char *modstr,
uint32_t srate, uint32_t fec, int pilot, int rolloff)
{
+ uint32_t freq = freq_Hz / 1000;
unsigned mod = dvb_parse_modulation (modstr, QPSK);
fec = dvb_parse_fec (fec);