Still do not have anything working, just trying to get some groundwork done.
SRCS-${CONFIG_LINUXDVB} += \
src/input/mpegts/linuxdvb/linuxdvb.c \
src/input/mpegts/linuxdvb/linuxdvb_adapter.c \
+ src/input/mpegts/linuxdvb/linuxdvb_frontend.c \
# src/input/mpegts/linuxdvb/linuxdvb_input.c \
# src/input/mpegts/linuxdvb/linuxdvb_network.c \
( mpegts_input_t *mi, const idclass_t *idc, const char *uuid );
#define mpegts_input_create(t, u)\
- (struct t*)mpegts_input_create0(calloc(1, sizeof(struct t)), t##_class, u)
+ (struct t*)mpegts_input_create0(calloc(1, sizeof(struct t)), &t##_class, u)
#define mpegts_input_create1(u)\
mpegts_input_create0(calloc(1, sizeof(mpegts_input_t)),\
const char *dvb_guard2str ( int guard );
const char *dvb_hier2str ( int hier );
const char *dvb_pol2str ( int pol );
+const char *dvb_type2str ( int type );
int dvb_str2rolloff ( const char *str );
int dvb_str2delsys ( const char *str );
int dvb_str2guard ( const char *str );
int dvb_str2hier ( const char *str );
int dvb_str2pol ( const char *str );
+int dvb_str2type ( const char *str );
#endif /* ENABLE_DVBAPI */
const char *dvb_##p##2str (int p) { return val2str(p, p##tab); }\
int dvb_str2##p (const char *p) { return str2val(p, p##tab); }
-static struct strtab rollofftab[] = {
+const static struct strtab rollofftab[] = {
#if DVB_API_VERSION >= 5
{ "ROLLOFF_35", ROLLOFF_35 },
{ "ROLLOFF_20", ROLLOFF_20 },
};
dvb_str2val(rolloff);
-static struct strtab delsystab[] = {
+const static struct strtab delsystab[] = {
#if DVB_API_VERSION >= 5
{ "SYS_UNDEFINED", SYS_UNDEFINED },
{ "SYS_DVBC_ANNEX_AC", SYS_DVBC_ANNEX_AC },
};
dvb_str2val(delsys);
-static struct strtab fectab[] = {
+const static struct strtab fectab[] = {
{ "NONE", FEC_NONE },
{ "1/2", FEC_1_2 },
{ "2/3", FEC_2_3 },
};
dvb_str2val(fec);
-static struct strtab qamtab[] = {
+const static struct strtab qamtab[] = {
{ "QPSK", QPSK },
{ "QAM16", QAM_16 },
{ "QAM32", QAM_32 },
};
dvb_str2val(qam);
-static struct strtab bwtab[] = {
+const static struct strtab bwtab[] = {
{ "8MHz", BANDWIDTH_8_MHZ },
{ "7MHz", BANDWIDTH_7_MHZ },
{ "6MHz", BANDWIDTH_6_MHZ },
};
dvb_str2val(bw);
-static struct strtab modetab[] = {
+const static struct strtab modetab[] = {
{ "2k", TRANSMISSION_MODE_2K },
{ "8k", TRANSMISSION_MODE_8K },
{ "AUTO", TRANSMISSION_MODE_AUTO },
};
dvb_str2val(mode);
-static struct strtab guardtab[] = {
+const static struct strtab guardtab[] = {
{ "1/32", GUARD_INTERVAL_1_32 },
{ "1/16", GUARD_INTERVAL_1_16 },
{ "1/8", GUARD_INTERVAL_1_8 },
};
dvb_str2val(guard);
-static struct strtab hiertab[] = {
+const static struct strtab hiertab[] = {
{ "NONE", HIERARCHY_NONE },
{ "1", HIERARCHY_1 },
{ "2", HIERARCHY_2 },
};
dvb_str2val(hier);
-static struct strtab poltab[] = {
+const static struct strtab poltab[] = {
{ "Vertical", POLARISATION_VERTICAL },
{ "Horizontal", POLARISATION_HORIZONTAL },
{ "Left", POLARISATION_CIRCULAR_LEFT },
};
dvb_str2val(pol);
+const static struct strtab typetab[] = {
+ {"DVB-T", FE_OFDM},
+ {"DVB-C", FE_QAM},
+ {"DVB-S", FE_QPSK},
+ {"ATSC", FE_ATSC},
+};
+dvb_str2val(type);
+
+
#undef dvb_str2val
#endif /* ENABLE_DVBAPI */
void linuxdvb_init ( int mask );
+idnode_t **linuxdvb_root ( void );
+
#endif /* __TVH_LINUX_DVB_H__ */
/******************************************************************************
#include "tvheadend.h"
#include "input.h"
+#include "settings.h"
#include "linuxdvb_private.h"
#include <sys/types.h>
void linuxdvb_init ( int adapter_mask )
{
- /* Scan for hardware */
int a;
- DIR *dp = opendir("/dev/dvb");
- struct dirent *de;
- while ((de = readdir(dp))) {
- if (sscanf(de->d_name, "adapter%d", &a) != 1) continue;
- if (a & adapter_mask)
- linuxdvb_adapter_create(a);
- }
+ DIR *dp;
+ htsmsg_t *s, *e;
+ htsmsg_field_t *f;
/* Load configuration */
- // TODO
+ if ((s = hts_settings_load_r(1, "input/linuxdvb/devices"))) {
+ HTSMSG_FOREACH(f, s) {
+ if ((e = htsmsg_get_map_by_field(f))) {
+ (void)linuxdvb_device_create0(f->hmf_name, e);
+ }
+ }
+ }
+
+ /* Scan for hardware */
+ if ((dp = opendir("/dev/dvb"))) {
+ struct dirent *de;
+ while ((de = readdir(dp))) {
+ if (sscanf(de->d_name, "adapter%d", &a) != 1) continue;
+ if ((0x1 << a) & adapter_mask)
+ linuxdvb_adapter_added(a);
+ }
+ }
+
+ // TODO: add udev support for hotplug
}
*/
#include "tvheadend.h"
+#include "input.h"
#include "linuxdvb_private.h"
+#include "queue.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <dirent.h>
#include <fcntl.h>
+/* ***************************************************************************
+ * DVB Hardware class
+ * **************************************************************************/
+
+static idnode_t **
+linuxdvb_hardware_enumerate ( linuxdvb_hardware_list_t *list )
+{
+ linuxdvb_hardware_t *lh;
+ idnode_t **v;
+ int cnt = 1;
+ LIST_FOREACH(lh, list, lh_parent_link)
+ cnt++;
+ v = malloc(sizeof(idnode_t *) * cnt);
+ cnt = 0;
+ LIST_FOREACH(lh, list, lh_parent_link)
+ v[cnt++] = &lh->mi_id;
+ v[cnt] = NULL;
+ return v;
+}
+
+static const char *
+linuxdvb_hardware_class_get_title ( idnode_t *in )
+{
+ return ((linuxdvb_hardware_t*)in)->lh_displayname;
+}
+
+static idnode_t **
+linuxdvb_hardware_class_get_childs ( idnode_t *in )
+{
+ return linuxdvb_hardware_enumerate(&((linuxdvb_hardware_t*)in)->lh_children);
+}
+
+const idclass_t linuxdvb_hardware_class =
+{
+ .ic_class = "linuxdvb_hardware",
+ .ic_caption = "LinuxDVB Hardware",
+ .ic_get_title = linuxdvb_hardware_class_get_title,
+ .ic_get_childs = linuxdvb_hardware_class_get_childs,
+ .ic_properties = (const property_t[]){
+ { PROPDEF1("enabled", "Enabled",
+ PT_BOOL, linuxdvb_hardware_t, lh_enabled) },
+ { PROPDEF1("displayname", "Name",
+ PT_STR, linuxdvb_hardware_t, lh_displayname) },
+ }
+};
+
+/* ***************************************************************************
+ * DVB Device
+ * **************************************************************************/
+
+/*
+ * BUS str table
+ */
+static struct strtab bustab[] = {
+ { "PCI", BUS_PCI },
+ { "USB1", BUS_USB1 },
+ { "USB2", BUS_USB2 },
+ { "USB3", BUS_USB3 }
+};
+static const char*
+devinfo_bus2str ( int p )
+{
+ return val2str(p, bustab);
+}
+
/*
* Get bus information
*/
-#if 0
static void
-get_host_connection ( linuxdvb_adapter_t *la, int a )
+get_device_info ( device_info_t *di, int a )
{
FILE *fp;
+ DIR *dp;
+ struct dirent *de;
+ uint16_t u16;
int speed;
char path[512], buf[512];
+ ssize_t c;
+ int mina = a;
/* Check for subsystem */
#define DVB_DEV_PATH "/sys/class/dvb/dvb%d.frontend0/device"
snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem", a);
- if (readlink(tpath, buf, sizeof(buf)) != -1) {
+ if ((c = readlink(path, buf, sizeof(buf))) != -1) {
+ buf[c] = '\0';
char *bus = basename(buf);
if (!strcmp(bus, "pci")) {
- i->bus = BUS_PCI;
+ di->di_bus = BUS_PCI;
+ snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem_vendor", a);
+ if ((fp = fopen(path, "r"))) {
+ if (fscanf(fp, "0x%hx", &u16) == 1)
+ di->di_dev = u16;
+ }
+ di->di_dev <<= 16;
+ snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem_device", a);
+ if ((fp = fopen(path, "r"))) {
+ if (fscanf(fp, "0x%hx", &u16) == 1)
+ di->di_dev |= u16;
+ }
+
} else if (!strcmp(bus, "usb")) {
- i->bus = BUS_USB1;
+ di->di_bus = BUS_USB1;
+ snprintf(path, sizeof(path), DVB_DEV_PATH "/idVendor", a);
+ if ((fp = fopen(path, "r"))) {
+ if (fscanf(fp, "%hx", &u16) == 1)
+ di->di_dev = u16;
+ }
+ di->di_dev <<= 16;
+ snprintf(path, sizeof(path), DVB_DEV_PATH "/idProduct", a);
+ if ((fp = fopen(path, "r"))) {
+ if (fscanf(fp, "%hx", &u16) == 1)
+ di->di_dev |= u16;
+ }
snprintf(path, sizeof(path), DVB_DEV_PATH "/speed", a);
if ((fp = fopen(path, "r"))) {
if (fscanf(fp, "%d", &speed) == 1) {
if (speed > 480) {
- i->bus = USB3;
+ di->di_bus = BUS_USB3;
} else if (speed == 480) {
- i->bus = USB2;
+ di->di_bus = BUS_USB2;
}
}
fclose(fp);
}
} else {
- tvhlog(LOG_WARN, "linuxdvb",
+ tvhlog(LOG_WARNING, "linuxdvb",
"could not determine host connection for adapter%d", a);
}
}
- /* Get ID */
+ /* Get Path */
snprintf(path, sizeof(path), DVB_DEV_PATH, a);
- if (readlink(tpath, buf, sizeof(buf)) != -1)
- strncpy(i->id, basename(buf), sizeof(i->id));
+ if ((c = readlink(path, buf, sizeof(buf))) != -1) {
+ buf[c] = '\0';
+ strcpy(di->di_path, basename(buf));
+ }
+
+ /* Find minimum adapter number */
+ snprintf(path, sizeof(path), DVB_DEV_PATH "/dvb", a);
+ if ((dp = opendir(path))) {
+ while ((de = readdir(dp))) {
+ int t;
+ if ((sscanf(de->d_name, "dvb%d.frontend0", &t)))
+ if (t < mina) mina = t;
+ }
+ closedir(dp);
+ }
+ di->di_min_adapter = mina;
+
+ /* Create ID */
+ if (*di->di_path && di->di_dev) {
+ snprintf(di->di_id, sizeof(di->di_id), "%s/%s/%04x:%04x",
+ devinfo_bus2str(di->di_bus), di->di_path,
+ di->di_dev >> 16, di->di_dev & 0xFFFF);
+ } else {
+ snprintf(di->di_id, sizeof(di->di_id), "/dev/dvb/adapter%d", a);
+ }
}
-#endif
+
+const idclass_t linuxdvb_device_class =
+{
+ .ic_super = &linuxdvb_hardware_class,
+ .ic_class = "linuxdvb_device",
+ .ic_caption = "LinuxDVB Device",
+ .ic_properties = (const property_t[]){
+ }
+};
+
+static linuxdvb_hardware_list_t linuxdvb_device_all;
+
+idnode_t **
+linuxdvb_root ( void )
+{
+ return linuxdvb_hardware_enumerate(&linuxdvb_device_all);
+}
+
+linuxdvb_device_t *
+linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf )
+{
+ uint32_t u32;
+ const char *str;
+ linuxdvb_device_t *ld;
+
+ /* Create */
+ ld = calloc(1, sizeof(linuxdvb_device_t));
+ if (idnode_insert(&ld->mi_id, uuid, &linuxdvb_device_class)) {
+ free(ld);
+ return NULL;
+ }
+ LIST_INSERT_HEAD(&linuxdvb_device_all, (linuxdvb_hardware_t*)ld, lh_parent_link);
+
+ /* No config */
+ if (!conf)
+ return ld;
+
+ /* Load config */
+ if (!htsmsg_get_u32(conf, "enabled", &u32) && u32)
+ ld->lh_enabled = 1;
+ if ((str = htsmsg_get_str(conf, "displayname")))
+ ld->lh_displayname = strdup(str);
+ if ((str = htsmsg_get_str(conf, "devid")))
+ strncpy(ld->ld_devid.di_id, str, sizeof(ld->ld_devid.di_id));
+
+ // TODO: adapters
+ // TODO: frontends
+
+ return ld;
+}
+
+static linuxdvb_device_t *
+linuxdvb_device_find_by_hwid ( const char *hwid )
+{
+ linuxdvb_hardware_t *lh;
+ LIST_FOREACH(lh, &linuxdvb_device_all, lh_parent_link)
+ if (!strcmp(hwid, ((linuxdvb_device_t*)lh)->ld_devid.di_id))
+ return (linuxdvb_device_t*)lh;
+ return NULL;
+}
+
+static linuxdvb_device_t *
+linuxdvb_device_find_by_adapter ( int a )
+{
+ linuxdvb_device_t *ld;
+ device_info_t dev;
+
+ /* Get device info */
+ get_device_info(&dev, a);
+
+ /* Find existing */
+ if ((ld = linuxdvb_device_find_by_hwid(dev.di_id)))
+ return ld;
+
+ /* Create new */
+ if (!(ld = linuxdvb_device_create0(NULL, NULL))) {
+ tvhlog(LOG_ERR, "linuxdvb", "failed to create device for adapter%d", a);
+ return NULL;
+ }
+
+ /* Copy device info */
+ memcpy(&ld->ld_devid, &dev, sizeof(dev));
+ ld->lh_displayname = strdup(dev.di_id);
+ return ld;
+}
+
+/* ***************************************************************************
+ * DVB Adapter
+ * **************************************************************************/
+
+const idclass_t linuxdvb_adapter_class =
+{
+ .ic_super = &linuxdvb_hardware_class,
+ .ic_class = "linuxdvb_adapter",
+ .ic_caption = "LinuxDVB Adapter",
+ .ic_properties = (const property_t[]){
+ }
+};
/*
* Check is free
*/
-static int
-linuxdvb_adapter_is_free ( mpegts_input_t *mi )
+int
+linuxdvb_adapter_is_free ( linuxdvb_adapter_t *la )
{
- linuxdvb_hardware_t *lh;
- linuxdvb_adapter_t *la = (linuxdvb_adapter_t*)mi;
-
- TAILQ_FOREACH(lh, &la->lh_childs, lh_parent_link)
- if (!lh->lh_is_free(lh))
- return 0;
- return 1;
+ return 0;
}
/*
* Get current weight
*/
-static int
-linuxdvb_adapter_current_weight ( mpegts_input_t *mi )
+int
+linuxdvb_adapter_current_weight ( linuxdvb_adapter_t *la )
+{
+ return 0;
+}
+
+/*
+ * Create
+ */
+static linuxdvb_adapter_t *
+linuxdvb_adapter_create0 ( const char *uuid, linuxdvb_device_t *ld, int n )
{
- int w = 0;
+ linuxdvb_adapter_t *la;
+
+ la = calloc(1, sizeof(linuxdvb_adapter_t));
+ if (idnode_insert(&la->mi_id, uuid, &linuxdvb_adapter_class)) {
+ free(la);
+ return NULL;
+ }
+ la->la_number = n;
+
+ LIST_INSERT_HEAD(&ld->lh_children, (linuxdvb_hardware_t*)la, lh_parent_link);
+ la->lh_parent = (linuxdvb_hardware_t*)ld;
+
+ return la;
+}
+
+/*
+ * Find existing adapter/device entry
+ */
+static linuxdvb_adapter_t *
+linuxdvb_adapter_find_by_number ( int adapter )
+{
+ int a;
+ char buf[1024];
linuxdvb_hardware_t *lh;
- linuxdvb_adapter_t *la = (linuxdvb_adapter_t*)mi;
+ linuxdvb_device_t *ld;
+ linuxdvb_adapter_t *la;
+
+ /* Find device */
+ if (!(ld = linuxdvb_device_find_by_adapter(adapter)))
+ return NULL;
+
+ /* Find existing adapter */
+ a = adapter - ld->ld_devid.di_min_adapter;
+ LIST_FOREACH(lh, &ld->lh_children, lh_parent_link) {
+ if (((linuxdvb_adapter_t*)lh)->la_number == a)
+ break;
+ }
+ la = (linuxdvb_adapter_t*)lh;
+
+ /* Create */
+ if (!la) {
+ if (!(la = linuxdvb_adapter_create0(NULL, ld, a)))
+ return NULL;
+ }
- TAILQ_FOREACH(lh, &la->lh_childs, lh_parent_link)
- w = MAX(w, lh->lh_current_weight(lh));
- return w;
+ /* Update */
+ snprintf(buf, sizeof(buf), "/dev/dvb/adapter%d", adapter);
+ tvh_str_update(&la->la_rootpath, buf);
+ if (!la->lh_displayname)
+ la->lh_displayname = strdup(la->la_rootpath);
+
+ return la;
}
/*
* Load an adapter
*/
linuxdvb_adapter_t *
-linuxdvb_adapter_create ( int adapter )
+linuxdvb_adapter_added ( int adapter )
{
int i, r, fd;
char fe_path[512], dmx_path[512], dvr_path[512];
if (access(dvr_path, R_OK | W_OK)) continue;
}
- /* Create adapter */
+ /* Create/Find adapter */
if (!la) {
- //la = linuxdvb_hardware_create(linuxdvb_adapter_t);
- la->mi_is_free = linuxdvb_adapter_is_free;
- la->mi_current_weight = linuxdvb_adapter_current_weight;
+ if (!(la = linuxdvb_adapter_find_by_number(adapter))) {
+ tvhlog(LOG_ERR, "linuxdvb", "failed to find/create adapter%d", adapter);
+ return NULL;
+ }
}
/* Create frontend */
- //linuxdvb_frontend_create(la, fe_path, dmx_path, dvr_path, &dfi);
+ tvhlog(LOG_DEBUG, "linuxdvb", "fe_create(%p, %s, %s, %s)",
+ la, fe_path, dmx_path, dvr_path);
+ linuxdvb_frontend_added(la, i, fe_path, dmx_path, dvr_path, &dfi);
}
return la;
}
+
+
#include "tvheadend.h"
#include "linuxdvb_private.h"
-#if 0
+#include <assert.h>
+
+/* **************************************************************************
+ * Class definitions
+ * *************************************************************************/
+
+extern const idclass_t linuxdvb_hardware_class;
+
+static const char *
+linuxdvb_frontend_class_get_title ( idnode_t *in )
+{
+ linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)in;
+ if (lfe->lh_displayname)
+ return lfe->lh_displayname;
+ if (lfe->lfe_fe_path)
+ return lfe->lfe_fe_path;
+ return "unknown";
+}
+
+const idclass_t linuxdvb_frontend_class =
+{
+ .ic_super = &linuxdvb_hardware_class,
+ .ic_class = "linuxdvb_frontend",
+ .ic_caption = "Linux DVB Frontend",
+ .ic_get_title = linuxdvb_frontend_class_get_title,
+ .ic_properties = (const property_t[]) {
+ }
+};
+
+const idclass_t linuxdvb_frontend_dvbt_class =
+{
+ .ic_super = &linuxdvb_frontend_class,
+ .ic_class = "linuxdvb_frontend_dvbt",
+ .ic_caption = "Linux DVB-T Frontend",
+ .ic_properties = (const property_t[]){
+ }
+};
+
+const idclass_t linuxdvb_frontend_dvbs_class =
+{
+ .ic_super = &linuxdvb_frontend_class,
+ .ic_class = "linuxdvb_frontend_dvbs",
+ .ic_caption = "Linux DVB-S Frontend",
+ .ic_properties = (const property_t[]){
+ }
+};
+
+const idclass_t linuxdvb_frontend_dvbc_class =
+{
+ .ic_super = &linuxdvb_frontend_class,
+ .ic_class = "linuxdvb_frontend_dvbc",
+ .ic_caption = "Linux DVB-C Frontend",
+ .ic_properties = (const property_t[]){
+ }
+};
+
+const idclass_t linuxdvb_frontend_atsc_class =
+{
+ .ic_super = &linuxdvb_frontend_class,
+ .ic_class = "linuxdvb_frontend_atsc",
+ .ic_caption = "Linux ATSC Frontend",
+ .ic_properties = (const property_t[]){
+ }
+};
+
+/* **************************************************************************
+ * Frontend
+ * *************************************************************************/
+
static int
linuxdvb_frontend_is_free ( mpegts_input_t *mi )
{
- linuxdvb_frontend_t *ldf = (linuxdvb_frontend_t*)mi;
- linuxdvb_adapter_t *lda = ldf->mi_adapter;
- LIST_FOREACH(ldf, &lda->lda_frontends, mi_adapter_link)
- if (!mpegts_input_is_free((mpegts_input_t*)ldf))
- return 0;
- return 1;
+#if 0
+ linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
+ linuxdvb_adapter_t *la = lfe->lfe_adapter;
+ return linuxdvb_adapter_is_free(la);
+#endif
+ return 0;
}
static int
linuxdvb_frontend_current_weight ( mpegts_input_t *mi )
{
- int w = 0;
- linuxdvb_frontend_t *ldf = (linuxdvb_frontend_t*)mi;
- linuxdvb_adapter_t *lda = ldf->mi_adapter;
- LIST_FOREACH(ldf, &lda->lda_frontends, mi_adapter_link)
- w = MAX(w, mpegts_input_current_weight((mpegts_input_t*)ldf));
- return w;
-}
+#if 0
+ linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
+ linuxdvb_adapter_t *la = lfe->lfe_adapter;
+ return linuxdvb_adapter_current_weight(la);
#endif
+ return 0;
+}
static void
linuxdvb_frontend_stop_mux
{
}
+#if 0
+#if DVB_API_VERSION >= 5
+
+static int
+linuxdvb_frontend_tune
+ ( linuxdvb_frontend_t *lfe, mpegts_mux_instance_t *mmi )
+{
+#if 0
+ struct dvb_frontend_event ev;
+ struct dvb_frontend_parameters *p = &dmc->dmc_fe_params;
+ int r;
+
+ /* Clear Q */
+ static struct dtv_property clear_p[] = {
+ { .cmd = DTV_CLEAR },
+ };
+ static struct dtv_properties clear_cmdseq = {
+ .num = 1,
+ .props = clear_p
+ };
+ if ((ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &clear_cmdseq)) != 0)
+ return -1;
+
+ /* Tune */
+ struct dtv_property _dvbs_cmdargs[] = {
+ { .cmd = DTV_DELIVERY_SYSTEM, .u.data = dmc->dmc_fe_delsys },
+ { .cmd = DTV_FREQUENCY, .u.data = p->frequency },
+ { .cmd = DTV_MODULATION, .u.data = dmc->dmc_fe_modulation },
+ { .cmd = DTV_SYMBOL_RATE, .u.data = p->u.qpsk.symbol_rate },
+ { .cmd = DTV_INNER_FEC, .u.data = p->u.qpsk.fec_inner },
+ { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO },
+ { .cmd = DTV_ROLLOFF, .u.data = dmc->dmc_fe_rolloff },
+ { .cmd = DTV_PILOT, .u.data = PILOT_AUTO },
+ { .cmd = DTV_TUNE },
+ };
+
+ struct dtv_properties _dvbs_cmdseq = {
+ .num = 9,
+ .props = _dvbs_cmdargs
+ };
+
+ /* discard stale QPSK events */
+ while (1) {
+ if (ioctl(tda->tda_fe_fd, FE_GET_EVENT, &ev) == -1)
+ break;
+ }
+
+ /* do tuning now */
+ r = ioctl(tda->tda_fe_fd, FE_SET_PROPERTY, &_dvbs_cmdseq);
+
+ return r;
+#endif
+ return 0;
+}
+
+#else
+static int
+linuxdvb_frontend_tune
+ ( linuxdvb_frontend_t *lfe, mpegts_mux_instance_t *mmi )
+{
+}
+
+#endif
+#endif
+
static int
linuxdvb_frontend_start_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
+#if 0
int r;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
mpegts_mux_instance_t *cur = LIST_FIRST(&mi->mi_mux_active);
}
assert(LIST_FIRST(&mi->mi_mux_active) == NULL);
- /* Start adapter */
- linuxdvb_adapter_start(lfe->lfe_parent);
-
/* Tune */
- r = ;
+ r = 0;//linuxdvb_frontend_tune(lfe, (linuxdvb_mux_t*)mmi);
/* Failed */
if (r != 0) {
tvhlog(LOG_ERR, "linuxdvb", "'%s' failed to tune '%s' error %s",
- lfe->lfe_path, "TODO", strerror(errno));
+ lfe->lfe_fe_path, "TODO", strerror(errno));
if (errno == EINVAL)
mmi->mmi_tune_failed = 1;
return SM_CODE_TUNING_FAILED;
/* Start monitor */
time(&lfe->lfe_monitor);
lfe->lfe_monitor += 4;
- gtiemr_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50);
+ //gtimer_arm_ms(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 50);
/* Send alert */
// TODO: should this be moved elsewhere?
+#endif
return 0;
}
-static int
+static void
linuxdvb_frontend_open_service
( mpegts_input_t *mi, mpegts_service_t *ms )
{
{
}
-linuxdvb_frontend_t *
-linuxdvb_frontend_create
- ( linuxdvb_adapter_t *adapter,
- const char *fe_path,
- const char *dmx_path,
- const char *dvr_path,
- const struct dvb_frontend_info *fe_info )
+static linuxdvb_frontend_t *
+linuxdvb_frontend_create0
+ ( const char *uuid, linuxdvb_adapter_t *la, int num, fe_type_t type )
{
const idclass_t *idc;
/* Class */
- if (fe_info->type == FE_QPSK)
+ if (type == FE_QPSK)
idc = &linuxdvb_frontend_dvbs_class;
- else if (fe_info->type == FE_QAM)
+ else if (type == FE_QAM)
idc = &linuxdvb_frontend_dvbc_class;
- else if (fe_info->type == FE_OFDM)
+ else if (type == FE_OFDM)
idc = &linuxdvb_frontend_dvbt_class;
- else if (fe_info->type == FE_ATSC)
+ else if (type == FE_ATSC)
idc = &linuxdvb_frontend_atsc_class;
else {
- tvhlog(LOG_ERR, "linuxdvb", "unknown FE type %d", fe_info->type);
+ tvhlog(LOG_ERR, "linuxdvb", "unknown FE type %d", type);
return NULL;
}
linuxdvb_frontend_t *lfe
- = mpegts_input_create0(calloc(1, sizeof(linuxdvb_frontend_t)), idc, NULL);
- lfe->lfe_fe_path = strdup(fe_path);
- lfe->lfe_dmx_path = strdup(dmx_path);
- lfe->lfe_dvr_path = strdup(dvr_path);
- memcpy(&lfe->lfe_fe_info, fe_info, sizeof(struct dvb_frontend_info));
+ = (linuxdvb_frontend_t*)
+ mpegts_input_create0(calloc(1, sizeof(linuxdvb_frontend_t)), idc, uuid);
+ /* Input callbacks */
lfe->mi_start_mux = linuxdvb_frontend_start_mux;
lfe->mi_stop_mux = linuxdvb_frontend_stop_mux;
lfe->mi_open_service = linuxdvb_frontend_open_service;
lfe->mi_is_free = linuxdvb_frontend_is_free;
lfe->mi_current_weight = linuxdvb_frontend_current_weight;
+ /* Adapter link */
+ lfe->lh_parent = (linuxdvb_hardware_t*)la;
+ LIST_INSERT_HEAD(&la->lh_children, (linuxdvb_hardware_t*)lfe, lh_parent_link);
+
+ return lfe;
+}
+
+linuxdvb_frontend_t *
+linuxdvb_frontend_added
+ ( linuxdvb_adapter_t *la, int fe_num,
+ const char *fe_path,
+ const char *dmx_path,
+ const char *dvr_path,
+ const struct dvb_frontend_info *fe_info )
+{
+ linuxdvb_hardware_t *lh;
+ linuxdvb_frontend_t *lfe = NULL;
+
+ /* Find existing */
+ LIST_FOREACH(lh, &la->lh_children, lh_parent_link) {
+ lfe = (linuxdvb_frontend_t*)lh;
+ if (lfe->lfe_number == fe_num) {
+ if (lfe->lfe_info.type != fe_info->type) {
+ tvhlog(LOG_ERR, "linuxdvb", "detected incorrect fe_type %s != %s",
+ dvb_type2str(lfe->lfe_info.type), dvb_type2str(fe_info->type));
+ return NULL;
+ }
+ break;
+ }
+ }
+
+ /* Create new */
+ if (!lfe) {
+ if (!(lfe = linuxdvb_frontend_create0(NULL, la, fe_num, fe_info->type))) {
+ tvhlog(LOG_ERR, "linuxdvb", "failed to create frontend");
+ return NULL;
+ }
+ }
+
+ /* Copy info */
+ memcpy(&lfe->lfe_info, fe_info, sizeof(struct dvb_frontend_info));
+
+ /* Set paths */
+ lfe->lfe_fe_path = strdup(fe_path);
+ lfe->lfe_dmx_path = strdup(dmx_path);
+ lfe->lfe_dvr_path = strdup(dvr_path);
+
return lfe;
}
#include "input/mpegts.h"
typedef struct linuxdvb_hardware linuxdvb_hardware_t;
+typedef struct linuxdvb_device linuxdvb_device_t;
typedef struct linuxdvb_adapter linuxdvb_adapter_t;
typedef struct linuxdvb_frontend linuxdvb_frontend_t;
-typedef TAILQ_HEAD(,linuxdvb_hardware) linuxdvb_hardware_queue_t;
+typedef LIST_HEAD(,linuxdvb_hardware) linuxdvb_hardware_list_t;
+
+typedef struct device_info
+{
+ char di_id[256];
+ char di_path[128];
+ enum {
+ BUS_NONE = 0,
+ BUS_PCI,
+ BUS_USB1,
+ BUS_USB2,
+ BUS_USB3
+ } di_bus;
+ uint32_t di_dev;
+ int di_min_adapter;
+} device_info_t;
struct linuxdvb_hardware
{
- mpegts_input_t; // this is actually redundant in HW
+ mpegts_input_t; // Note: this is redundant in many of the instances
+ // but we can't do multiple-inheritance and this
+ // keeps some of the code clean
- /* HW tree */
- linuxdvb_hardware_t *lh_parent;
- TAILQ_ENTRY(linuxdvb_hardware) lh_parent_link;
- TAILQ_HEAD(,linuxdvb_hardware) lh_childs;
+ /*
+ * Parent/Child links
+ */
+ linuxdvb_hardware_t *lh_parent;
+ LIST_ENTRY(linuxdvb_hardware) lh_parent_link;
+ linuxdvb_hardware_list_t lh_children;
+
+ /*
+ * Device info
+ */
+ int lh_enabled;
+ char *lh_displayname;
+};
+
+struct linuxdvb_device
+{
+ linuxdvb_hardware_t;
- /* These replicate the mpegts_input_t callbacks but work down the tree */
- int (*lh_is_free) (linuxdvb_hardware_t *lh);
- int (*lh_current_weight) (linuxdvb_hardware_t *lh);
+ /*
+ * Device info
+ */
+ device_info_t ld_devid;
};
+linuxdvb_device_t *linuxdvb_device_create0
+ (const char *uuid, htsmsg_t *conf);
+
struct linuxdvb_adapter
{
linuxdvb_hardware_t;
/*
- * Hardware info
+ * Adapter info
*/
- char *la_path;
- char *la_dev_id;
- enum {
- BUS_NONE = 0,
- BUS_PCI,
- BUS_USB1,
- BUS_USB2,
- BUS_USB3
- } la_dev_bus;
+ char *la_rootpath;
+ uint32_t la_number;
};
-linuxdvb_adapter_t *linuxdvb_adapter_create (int a);
+#define LINUXDVB_SUBSYS_FE 0x01
+#define LINUXDVB_SUBSYS_DVR 0x02
+
+linuxdvb_adapter_t *linuxdvb_adapter_added (int a);
+
+int linuxdvb_adapter_is_free ( linuxdvb_adapter_t *la );
+int linuxdvb_adapter_current_weight ( linuxdvb_adapter_t *la );
+
+linuxdvb_adapter_t *linuxdvb_adapter_find_by_hwid ( const char *hwid );
+linuxdvb_adapter_t *linuxdvb_adapter_find_by_path ( const char *path );
struct linuxdvb_frontend
{
/*
* Frontend info
*/
- struct dvb_frontend_info lfe_fe_info;
+ int lfe_number;
+ struct dvb_frontend_info lfe_info;
char *lfe_fe_path;
- char lfe_dmx_path;
- char lfe_dvr_path;
+ char *lfe_dmx_path;
+ char *lfe_dvr_path;
+
+ /*
+ * Tuning
+ */
+ time_t lfe_monitor;
+ gtimer_t lfe_monitor_timer;
};
-linuxdvb_frontend_t *linuxdvb_frontend_create
- ( linuxdvb_adapter_t *la, const char *fe_path,
- const char *dmx_path, const char *dvr_path,
+linuxdvb_frontend_t *
+linuxdvb_frontend_added
+ ( linuxdvb_adapter_t *la, int fe_num,
+ const char *fe_path, const char *dmx_path, const char *dvr_path,
const struct dvb_frontend_info *fe_info );
#endif /* __TVH_LINUXDVB_PRIVATE_H__ */
#include "imagecache.h"
#include "timeshift.h"
#include "tvhtime.h"
-
-#if 0
-#include "tvadapters.h"
-#endif
+#include "input.h"
/**
*
out = htsmsg_create_list();
idnode_t **v;
+printf("get(%s)\n", s);
if(!strcmp(s, "root")) {
v = rootfn();
} else {
/**
*
*/
-#ifdef TODO_FIX_THIS
static int
extjs_tvadapters(http_connection_t *hc, const char *remain, void *opaque)
{
- return extjs_get_idnode(hc, remain, opaque, &tv_adapters_root);
+ return extjs_get_idnode(hc, remain, opaque, &linuxdvb_root);
}
-#endif
http_path_add("/tvhlog", NULL, extjs_tvhlog, ACCESS_ADMIN);
http_path_add("/item/update", NULL, extjs_item_update, ACCESS_ADMIN);
-#ifdef TODO_FIX_THIS
http_path_add("/tvadapters",
NULL, extjs_tvadapters, ACCESS_ADMIN);
-#endif
#if 0//ENABLE_LINUXDVB
extjs_start_dvb();
*/
tvheadend.tvadapters = function() {
- return tvheadend.item_browser('/tvadapters', 'TV Adapters');
+ return tvheadend.item_browser('tvadapters', 'TV Adapters');
}