]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
linuxdvb: starting to build up the DVB hardware tree
authorAdam Sutton <dev@adamsutton.me.uk>
Fri, 24 May 2013 12:59:19 +0000 (13:59 +0100)
committerAdam Sutton <dev@adamsutton.me.uk>
Fri, 24 May 2013 12:59:19 +0000 (13:59 +0100)
Still do not have anything working, just trying to get some groundwork done.

Makefile
src/input/mpegts.h
src/input/mpegts/dvb.h
src/input/mpegts/dvb_support.c
src/input/mpegts/linuxdvb.h
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_private.h
src/webui/extjs.c
src/webui/static/app/tvadapters.js

index a4b4619ee3278668b89f99509410d8d416b1c1da..1c2680efe625616629c7400f053a7d72afd4c3ff 100644 (file)
--- 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 \
index b244f71d21bf3cfdc7605851e2616188df798fc9..e4c753883d333ef71b97c71e4efe56461396be1e 100644 (file)
@@ -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)),\
index fd6ccd9e006d059779e75b5061dcbee06d824e55..2a058a8380de3583fb40d325fba8bc4304abaa80 100644 (file)
@@ -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 */
 
index f342e9544603c891fe72222c09419aa39d052c07..828329e1740ad1c416c4b5206707e6435af11d3d 100644 (file)
@@ -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 */
index 603efb99cf1cb98c8dfbdb30e048226e07c3228b..7b45171fb89c504fa1d5cc93ce7f6230b266ab21 100644 (file)
@@ -22,6 +22,8 @@
 
 void linuxdvb_init ( int mask );
 
+idnode_t **linuxdvb_root ( void );
+
 #endif /* __TVH_LINUX_DVB_H__ */
 
 /******************************************************************************
index b18ed58c8dbe740855066360e7ebbd0f011bb793..b2e96cdcdbb5f1d65ff5c3c8797ef49032733d84 100644 (file)
@@ -19,6 +19,7 @@
 
 #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
 }
index f82162b06e8d150e42168c16694458e60067d0a1..ef7553cbf1a9d46ee146682d4d74b56fd31fd58c 100644 (file)
@@ -18,7 +18,9 @@
  */
 
 #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];
@@ -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;
 }
+
+
index 003cb148ae642cd8426868f40ccb73c552e8ac72..7259a3e7f2be2e8529dcd0cd57db577808ada087 100644 (file)
 #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
@@ -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;
 }
index 5fda2b47219ebbb96e095dff62d3b36ba3afd0e1..7db6ec44184156a062310bb0a50a5ddfd4d32061 100644 (file)
 #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__ */
index 341847709fffde79b25e7b2379620701593b807f..e1678b1f2a23f740bb0dbdeeba4d9cb83b460b50 100644 (file)
 #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();
index ef2fcba6bb5171efd86c28981f2dd6fda848afb0..c13e209f8be2dba6caa977d260931e45d79f8f6f 100644 (file)
@@ -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');
 }