From: Adam Sutton Date: Fri, 24 May 2013 12:59:19 +0000 (+0100) Subject: linuxdvb: starting to build up the DVB hardware tree X-Git-Tag: v3.9^2~194 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=8b82a8290142a2eb7b2c588ea46d41433b1895a1;p=thirdparty%2Ftvheadend.git linuxdvb: starting to build up the DVB hardware tree Still do not have anything working, just trying to get some groundwork done. --- diff --git a/Makefile b/Makefile index a4b4619ee..1c2680efe 100644 --- a/Makefile +++ b/Makefile @@ -168,6 +168,7 @@ SRCS-$(CONFIG_MPEGTS) += \ 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 \ diff --git a/src/input/mpegts.h b/src/input/mpegts.h index b244f71d2..e4c753883 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -431,7 +431,7 @@ mpegts_input_t *mpegts_input_create0 ( 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)),\ diff --git a/src/input/mpegts/dvb.h b/src/input/mpegts/dvb.h index fd6ccd9e0..2a058a838 100644 --- a/src/input/mpegts/dvb.h +++ b/src/input/mpegts/dvb.h @@ -208,6 +208,7 @@ const char *dvb_mode2str ( int mode ); 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 ); @@ -218,6 +219,7 @@ int dvb_str2mode ( 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 */ diff --git a/src/input/mpegts/dvb_support.c b/src/input/mpegts/dvb_support.c index f342e9544..828329e17 100644 --- a/src/input/mpegts/dvb_support.c +++ b/src/input/mpegts/dvb_support.c @@ -379,7 +379,7 @@ dvb_convert_date(uint8_t *dvb_buf) 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 }, @@ -389,7 +389,7 @@ static struct strtab rollofftab[] = { }; 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 }, @@ -411,7 +411,7 @@ static struct strtab delsystab[] = { }; 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 }, @@ -429,7 +429,7 @@ static struct strtab fectab[] = { }; dvb_str2val(fec); -static struct strtab qamtab[] = { +const static struct strtab qamtab[] = { { "QPSK", QPSK }, { "QAM16", QAM_16 }, { "QAM32", QAM_32 }, @@ -448,7 +448,7 @@ static struct strtab qamtab[] = { }; dvb_str2val(qam); -static struct strtab bwtab[] = { +const static struct strtab bwtab[] = { { "8MHz", BANDWIDTH_8_MHZ }, { "7MHz", BANDWIDTH_7_MHZ }, { "6MHz", BANDWIDTH_6_MHZ }, @@ -461,7 +461,7 @@ static struct strtab bwtab[] = { }; dvb_str2val(bw); -static struct strtab modetab[] = { +const static struct strtab modetab[] = { { "2k", TRANSMISSION_MODE_2K }, { "8k", TRANSMISSION_MODE_8K }, { "AUTO", TRANSMISSION_MODE_AUTO }, @@ -473,7 +473,7 @@ static struct strtab modetab[] = { }; 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 }, @@ -487,7 +487,7 @@ static struct strtab guardtab[] = { }; dvb_str2val(guard); -static struct strtab hiertab[] = { +const static struct strtab hiertab[] = { { "NONE", HIERARCHY_NONE }, { "1", HIERARCHY_1 }, { "2", HIERARCHY_2 }, @@ -496,7 +496,7 @@ static struct strtab hiertab[] = { }; dvb_str2val(hier); -static struct strtab poltab[] = { +const static struct strtab poltab[] = { { "Vertical", POLARISATION_VERTICAL }, { "Horizontal", POLARISATION_HORIZONTAL }, { "Left", POLARISATION_CIRCULAR_LEFT }, @@ -504,6 +504,15 @@ static struct strtab poltab[] = { }; 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 */ diff --git a/src/input/mpegts/linuxdvb.h b/src/input/mpegts/linuxdvb.h index 603efb99c..7b45171fb 100644 --- a/src/input/mpegts/linuxdvb.h +++ b/src/input/mpegts/linuxdvb.h @@ -22,6 +22,8 @@ void linuxdvb_init ( int mask ); +idnode_t **linuxdvb_root ( void ); + #endif /* __TVH_LINUX_DVB_H__ */ /****************************************************************************** diff --git a/src/input/mpegts/linuxdvb/linuxdvb.c b/src/input/mpegts/linuxdvb/linuxdvb.c index b18ed58c8..b2e96cdcd 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb.c +++ b/src/input/mpegts/linuxdvb/linuxdvb.c @@ -19,6 +19,7 @@ #include "tvheadend.h" #include "input.h" +#include "settings.h" #include "linuxdvb_private.h" #include @@ -26,16 +27,29 @@ 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 } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c index f82162b06..ef7553cbf 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c @@ -18,7 +18,9 @@ */ #include "tvheadend.h" +#include "input.h" #include "linuxdvb_private.h" +#include "queue.h" #include #include @@ -27,85 +29,346 @@ #include #include +/* *************************************************************************** + * 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]; @@ -145,16 +408,21 @@ linuxdvb_adapter_create ( int adapter ) 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; } + + diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index 003cb148a..7259a3e7f 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -20,29 +20,96 @@ #include "tvheadend.h" #include "linuxdvb_private.h" -#if 0 +#include + +/* ************************************************************************** + * 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 @@ -50,10 +117,76 @@ 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); @@ -70,16 +203,13 @@ linuxdvb_frontend_start_mux } 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; @@ -88,15 +218,16 @@ linuxdvb_frontend_start_mux /* 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 ) { @@ -108,37 +239,31 @@ linuxdvb_frontend_close_service { } -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; @@ -146,5 +271,52 @@ linuxdvb_frontend_create 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; } diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index 5fda2b472..7db6ec441 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -23,44 +23,81 @@ #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 { @@ -69,15 +106,23 @@ 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__ */ diff --git a/src/webui/extjs.c b/src/webui/extjs.c index 341847709..e1678b1f2 100644 --- a/src/webui/extjs.c +++ b/src/webui/extjs.c @@ -48,10 +48,7 @@ #include "imagecache.h" #include "timeshift.h" #include "tvhtime.h" - -#if 0 -#include "tvadapters.h" -#endif +#include "input.h" /** * @@ -2181,6 +2178,7 @@ extjs_get_idnode(http_connection_t *hc, const char *remain, void *opaque, out = htsmsg_create_list(); idnode_t **v; +printf("get(%s)\n", s); if(!strcmp(s, "root")) { v = rootfn(); } else { @@ -2251,13 +2249,11 @@ extjs_item_update(http_connection_t *hc, const char *remain, void *opaque) /** * */ -#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 @@ -2386,10 +2382,8 @@ extjs_start(void) 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(); diff --git a/src/webui/static/app/tvadapters.js b/src/webui/static/app/tvadapters.js index ef2fcba6b..c13e209f8 100644 --- a/src/webui/static/app/tvadapters.js +++ b/src/webui/static/app/tvadapters.js @@ -113,5 +113,5 @@ tvheadend.showTransportDetails = function(data) { */ tvheadend.tvadapters = function() { - return tvheadend.item_browser('/tvadapters', 'TV Adapters'); + return tvheadend.item_browser('tvadapters', 'TV Adapters'); }