#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/epoll.h>
+#include <sys/types.h>
+#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
struct th_dvb_adapter_queue dvb_adapters;
struct th_dvb_mux_instance_tree dvb_muxes;
static void *dvb_adapter_input_dvr(void *aux);
+static void tda_init(th_dvb_adapter_t *tda);
/**
lock_assert(&global_lock);
htsmsg_add_u32(m, "enabled", tda->tda_enabled);
+ if (tda->tda_fe_path)
+ htsmsg_add_str(m, "fe_path", tda->tda_fe_path);
+ if (tda->tda_demux_path)
+ htsmsg_add_str(m, "dmx_path", tda->tda_demux_path);
+ if (tda->tda_dvr_path)
+ htsmsg_add_str(m, "dvr_path", tda->tda_dvr_path);
htsmsg_add_str(m, "type", dvb_adaptertype_to_str(tda->tda_type));
htsmsg_add_str(m, "displayname", tda->tda_displayname);
htsmsg_add_u32(m, "autodiscovery", tda->tda_autodiscovery);
htsmsg_destroy(m);
}
+/**
+ *
+ */
+void
+dvb_adapter_set_enabled(th_dvb_adapter_t *tda, int on)
+{
+ if(tda->tda_enabled == on)
+ return;
+
+ lock_assert(&global_lock);
+
+ tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" %s",
+ tda->tda_displayname, on ? "Enabled" : "Disabled");
+
+ tda->tda_enabled = on;
+ tda_save(tda);
+ if (!on) {
+ gtimer_disarm(&tda->tda_mux_scanner_timer);
+ if (tda->tda_mux_current)
+ dvb_fe_stop(tda->tda_mux_current, 0);
+ dvb_adapter_stop(tda);
+ } else {
+ tda_init(tda);
+ }
+}
/**
*
dvb_adapter_notify(tda);
}
-
-/**
- *
- */
-void
-dvb_adapter_set_enabled(th_dvb_adapter_t *tda, uint32_t enabled)
-{
- if(tda->tda_enabled == enabled)
- return;
-
- lock_assert(&global_lock);
-
- tvhlog(LOG_NOTICE, "dvb", "Adapter \"%s\" enabled set to \"%s\"",
- tda->tda_displayname, enabled ? "Enabled" : "Disabled");
-
- tda->tda_enabled = enabled;
- tda_save(tda);
-}
-
-
/**
*
*/
*
*/
static void
-tda_add(int adapter_num, int frontend_num, int demux_num)
+tda_add(int adapter_num)
{
- char path[200], fname[256];
- int fe, i, r;
+ char buf[1024], path[200], fepath[256], dmxpath[256], dvrpath[256];
+ int i, j, fd;
th_dvb_adapter_t *tda;
- char buf[400];
+ struct dvb_frontend_info fe_info;
+ DIR *dirp;
+ /* Check valid adapter */
snprintf(path, sizeof(path), "/dev/dvb/adapter%d", adapter_num);
- snprintf(fname, sizeof(fname), "%s/frontend%d", path, frontend_num);
-
- fe = tvh_open(fname, O_RDWR | O_NONBLOCK, 0);
- if(fe == -1) {
- if(errno != ENOENT)
- tvhlog(LOG_ALERT, "dvb",
- "Unable to open %s -- %s", fname, strerror(errno));
+ dirp = opendir(path);
+ if (!dirp)
return;
- }
-
- tda = tda_alloc();
-
- tda->tda_adapter_num = adapter_num;
- tda->tda_rootpath = strdup(path);
- tda->tda_demux_path = malloc(256);
- snprintf(tda->tda_demux_path, 256, "%s/demux%d", path, demux_num);
- tda->tda_fe_path = strdup(fname);
- tda->tda_fe_fd = -1;
- tda->tda_dvr_pipe.rd = -1;
- tda->tda_full_mux_rx = -1;
- tda->tda_enabled = 0;
- tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info));
-
- if(ioctl(fe, FE_GET_INFO, tda->tda_fe_info)) {
- tvhlog(LOG_ALERT, "dvb", "%s: Unable to query adapter", fname);
- close(fe);
- free(tda);
- return;
+ /* Check each frontend */
+ // Note: this algo will fail if there are really exotic variations
+ // of tuners and demuxers etc... but you can always manually
+ // override the config
+ for (i = 0; i < 32; i++) {
+
+ /* Open/Query frontend */
+ snprintf(fepath, sizeof(fepath), "%s/frontend%d", path, i);
+ fd = tvh_open(fepath, O_RDONLY, 0);
+ if (fd == -1) {
+ if (errno != ENOENT)
+ tvhlog(LOG_ALERT, "dvb",
+ "%s: unable to open (err=%s)", fepath, strerror(errno));
+ continue;
+ }
+ if (ioctl(fd, FE_GET_INFO, &fe_info)) {
+ tvhlog(LOG_ALERT, "dvb",
+ "%s: unable to query (err=%s)", fepath, strerror(errno));
+ close(fd);
+ continue;
+ }
+ close(fd);
+
+ /* Find Demux */
+ snprintf(dmxpath, sizeof(dmxpath), "%s/demux%d", path, i);
+ fd = tvh_open(dmxpath, O_RDONLY, 0);
+ if (fd == -1) {
+ snprintf(dmxpath, sizeof(dmxpath), "%s/demux%d", path, 0);
+ fd = tvh_open(dmxpath, O_RDONLY, 0);
+ }
+ if (fd == -1) {
+ tvhlog(LOG_ALERT, "dvb", "%s: unable to find demux", fepath);
+ continue;
+ }
+ close(fd);
+
+ /* Find DVR */
+ snprintf(dvrpath, sizeof(dvrpath), "%s/dvr%d", path, i);
+ fd = tvh_open(dvrpath, O_RDONLY, 0);
+ if (fd == -1) {
+ snprintf(dvrpath, sizeof(dvrpath), "%s/dvr%d", path, 0);
+ fd = tvh_open(dvrpath, O_RDONLY, 0);
+ }
+ if (fd == -1) {
+ tvhlog(LOG_ALERT, "dvb", "%s: unable to find dvr", fepath);
+ continue;
+ }
+ close(fd);
+
+ /* Create entry */
+ tda = tda_alloc();
+ tda->tda_adapter_num = adapter_num;
+ tda->tda_rootpath = strdup(path);
+ tda->tda_fe_path = strdup(fepath);
+ tda->tda_demux_path = strdup(dmxpath);
+ tda->tda_dvr_path = strdup(dvrpath);
+ tda->tda_fe_fd = -1;
+ tda->tda_dvr_pipe.rd = -1;
+ tda->tda_full_mux_rx = -1;
+ tda->tda_type = fe_info.type;
+ tda->tda_autodiscovery = tda->tda_type != FE_QPSK;
+ tda->tda_idlescan = 1;
+ tda->tda_sat = tda->tda_type == FE_QPSK;
+ tda->tda_displayname = strdup(fe_info.name);
+ tda->tda_fe_info = malloc(sizeof(struct dvb_frontend_info));
+ memcpy(tda->tda_fe_info, &fe_info, sizeof(struct dvb_frontend_info));
+
+ /* ID the device (for configuration etc..) */
+ // Note: would be better to include frontend dev in name, but that
+ // would require additional work to migrate config
+ snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath,
+ tda->tda_fe_info->name);
+ for(j = 0; j < strlen(buf); j++)
+ if(!isalnum((int)buf[j]))
+ buf[j] = '_';
+ tda->tda_identifier = strdup(buf);
+
+ /* Check device connection */
+ dvb_adapter_checkspeed(tda);
+
+ /* Adapters known to provide valid SNR */
+ if(strcasestr(fe_info.name, "Sony CXD2820R"))
+ tda->tda_snr_valid = 1;
+
+ /* Store */
+ tvhlog(LOG_INFO, "dvb",
+ "Found adapter %s (%s) via %s%s", path, tda->tda_fe_info->name,
+ hostconnection2str(tda->tda_hostconnection),
+ tda->tda_snr_valid ? ", Reports valid SNR values" : "");
+ TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link);
}
-
- close(fe);
- fe = -1;
-
- tda->tda_type = tda->tda_fe_info->type;
-
- snprintf(buf, sizeof(buf), "%s_%s", tda->tda_rootpath,
- tda->tda_fe_info->name);
-
- r = strlen(buf);
- for(i = 0; i < r; i++)
- if(!isalnum((int)buf[i]))
- buf[i] = '_';
-
- tda->tda_identifier = strdup(buf);
-
- tda->tda_autodiscovery = tda->tda_type != FE_QPSK;
- tda->tda_idlescan = 1;
-
- tda->tda_sat = tda->tda_type == FE_QPSK;
-
- /* Come up with an initial displayname, user can change it and it will
- be overridden by any stored settings later on */
-
- tda->tda_displayname = strdup(tda->tda_fe_info->name);
-
- dvb_adapter_checkspeed(tda);
-
-
- if(strcasestr(tda->tda_fe_info->name, "Sony CXD2820R"))
- tda->tda_snr_valid = 1;
-
- tvhlog(LOG_INFO, "dvb",
- "Found adapter %s (%s) via %s%s", path, tda->tda_fe_info->name,
- hostconnection2str(tda->tda_hostconnection),
- tda->tda_snr_valid ? ", Reports valid SNR values" : "");
-
- TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link);
-
- gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1);
}
-
-
/**
*
*/
}
/**
- * Initiliase input
+ * Initiliase
*/
-static void tda_init_input (th_dvb_adapter_t *tda)
+static void tda_init (th_dvb_adapter_t *tda)
{
- if(tda->tda_type == -1 || check_full_stream(tda)) {
- tvhlog(LOG_INFO, "dvb", "Adapter %s will run in full mux mode", tda->tda_rootpath);
- dvb_input_raw_setup(tda);
- } else {
- tvhlog(LOG_INFO, "dvb", "Adapter %s will run in filtered mode", tda->tda_rootpath);
- dvb_input_filtered_setup(tda);
+ /* Disabled - ignore */
+ if (!tda->tda_enabled || !tda->tda_rootpath) return;
+
+ /* Initiliase input mode */
+ if(!tda->tda_open_service) {
+ if(tda->tda_type == -1 || check_full_stream(tda)) {
+ tvhlog(LOG_INFO, "dvb", "Adapter %s will run in full mux mode", tda->tda_rootpath);
+ dvb_input_raw_setup(tda);
+ } else {
+ tvhlog(LOG_INFO, "dvb", "Adapter %s will run in filtered mode", tda->tda_rootpath);
+ dvb_input_filtered_setup(tda);
+ }
}
-}
-
+ /* Enable mux scanner */
+ gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 1);
+}
/**
*
dvb_adapter_poweroff(tda);
/* Don't stop/close */
- if (!tda->tda_idleclose) return;
+ if (!tda->tda_idleclose && tda->tda_enabled) return;
/* Close front end */
if (tda->tda_fe_fd != -1) {
tda->tda_dvr_pipe.rd = -1;
tvhlog(LOG_DEBUG, "dvb", "%s stopped thread", tda->tda_rootpath);
}
+
+ dvb_adapter_notify(tda);
}
/**
{
htsmsg_t *l, *c;
htsmsg_field_t *f;
- const char *name, *s;
- int i, j, type;
+ const char *s;
+ int i, type;
uint32_t u32;
th_dvb_adapter_t *tda;
/* Initialise hardware */
for(i = 0; i < 32; i++)
if ((1 << i) & adapter_mask)
- for(j = 0; j < 32; j++)
- tda_add(i, j, 0);
+ tda_add(i);
/* Initialise rawts test file */
if(rawfile)
tda_add_from_file(rawfile);
/* Load configuration */
- l = hts_settings_load("dvbadapters");
- if(l != NULL) {
+ if ((l = hts_settings_load("dvbadapters")) != NULL) {
HTSMSG_FOREACH(f, l) {
if((c = htsmsg_get_map_by_field(f)) == NULL)
continue;
- name = htsmsg_get_str(c, "displayname");
-
if((s = htsmsg_get_str(c, "type")) == NULL ||
(type = dvb_str_to_adaptertype(s)) < 0)
continue;
+ // TODO: do we really want to do this? useful for debug?
if((tda = dvb_adapter_find_by_identifier(f->hmf_name)) == NULL) {
/* Not discovered by hardware, create it */
- tda = tda_alloc();
+ tda = tda_alloc();
tda->tda_identifier = strdup(f->hmf_name);
- tda->tda_type = type;
- tda->tda_enabled = 0;
+ tda->tda_type = type;
TAILQ_INSERT_TAIL(&dvb_adapters, tda, tda_global_link);
} else {
if(type != tda->tda_type)
continue; /* Something is wrong, ignore */
}
- free(tda->tda_displayname);
- tda->tda_displayname = strdup(name);
-
- htsmsg_get_u32(c, "enabled", &tda->tda_enabled);
- htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery);
- htsmsg_get_u32(c, "idlescan", &tda->tda_idlescan);
- htsmsg_get_u32(c, "idleclose", &tda->tda_idleclose);
- htsmsg_get_u32(c, "skip_checksubscr", &tda->tda_skip_checksubscr);
- htsmsg_get_u32(c, "sidtochan", &tda->tda_sidtochan);
- htsmsg_get_u32(c, "qmon", &tda->tda_qmon);
- htsmsg_get_u32(c, "poweroff", &tda->tda_poweroff);
- htsmsg_get_u32(c, "nitoid", &tda->tda_nitoid);
- htsmsg_get_u32(c, "diseqc_version", &tda->tda_diseqc_version);
- htsmsg_get_u32(c, "diseqc_repeats", &tda->tda_diseqc_repeats);
- htsmsg_get_u32(c, "extrapriority", &tda->tda_extrapriority);
- htsmsg_get_u32(c, "skip_initialscan", &tda->tda_skip_initialscan);
+ tvh_str_update(&tda->tda_displayname, htsmsg_get_str(c, "displayname"));
+ tvh_str_update(&tda->tda_dvr_path, htsmsg_get_str(c, "dvr_path"));
+ tvh_str_update(&tda->tda_demux_path, htsmsg_get_str(c, "dmx_path"));
+
+ if (htsmsg_get_u32(c, "enabled", &tda->tda_enabled))
+ tda->tda_enabled = 1;
+ htsmsg_get_u32(c, "autodiscovery", &tda->tda_autodiscovery);
+ htsmsg_get_u32(c, "idlescan", &tda->tda_idlescan);
+ htsmsg_get_u32(c, "idleclose", &tda->tda_idleclose);
+ htsmsg_get_u32(c, "skip_checksubscr", &tda->tda_skip_checksubscr);
+ htsmsg_get_u32(c, "sidtochan", &tda->tda_sidtochan);
+ htsmsg_get_u32(c, "qmon", &tda->tda_qmon);
+ htsmsg_get_u32(c, "poweroff", &tda->tda_poweroff);
+ htsmsg_get_u32(c, "nitoid", &tda->tda_nitoid);
+ htsmsg_get_u32(c, "diseqc_version", &tda->tda_diseqc_version);
+ htsmsg_get_u32(c, "diseqc_repeats", &tda->tda_diseqc_repeats);
+ htsmsg_get_u32(c, "extrapriority", &tda->tda_extrapriority);
+ htsmsg_get_u32(c, "skip_initialscan", &tda->tda_skip_initialscan);
htsmsg_get_u32(c, "disable_pmt_monitor", &tda->tda_disable_pmt_monitor);
if (htsmsg_get_s32(c, "full_mux_rx", &tda->tda_full_mux_rx))
if (!htsmsg_get_u32(c, "disable_full_mux_rx", &u32) && u32)
htsmsg_destroy(l);
}
+ /* Initialise devices */
TAILQ_FOREACH(tda, &dvb_adapters, tda_global_link) {
- tda_init_input(tda);
- if (tda->tda_idlescan || !tda->tda_idleclose) {
- close(tda->tda_fe_fd);
- tda->tda_fe_fd = -1;
- }
+ tda_init(tda);
if(tda->tda_sat)
dvb_satconf_init(tda);
if(tda->tda_rootpath == NULL)
return; // No hardware
+ if(!tda->tda_enabled)
+ return; // disabled
+
// default period
gtimer_arm(&tda->tda_mux_scanner_timer, dvb_adapter_mux_scanner, tda, 20);
uint8_t tsb[188 * 10];
service_t *t;
struct epoll_event ev;
- char path[256];
- snprintf(path, sizeof(path), "%s/dvr0", tda->tda_rootpath);
-
- fd = tvh_open(path, O_RDONLY | O_NONBLOCK, 0);
+ fd = tvh_open(tda->tda_dvr_path, O_RDONLY | O_NONBLOCK, 0);
if(fd == -1) {
- tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s", path, strerror(errno));
+ tvhlog(LOG_ALERT, "dvb", "Unable to open %s -- %s", tda->tda_dvr_path, strerror(errno));
return NULL;
}
htsmsg_add_u32(m, "ber", tdmi->tdmi_ber);
htsmsg_add_u32(m, "unc", tdmi->tdmi_unc);
htsmsg_add_u32(m, "uncavg", tdmi->tdmi_unc_avg);
+ } else {
+ htsmsg_add_str(m, "currentMux", "");
+ htsmsg_add_u32(m, "signal", 0);
+ htsmsg_add_u32(m, "snr", 0);
+ htsmsg_add_u32(m, "ber", 0);
+ htsmsg_add_u32(m, "unc", 0);
+ htsmsg_add_u32(m, "uncavg", 0);
}
if(tda->tda_rootpath == NULL)