]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
linuxdvb: add master tuner support, fixes #2952
authorJaroslav Kysela <perex@perex.cz>
Sun, 4 Oct 2015 14:48:26 +0000 (16:48 +0200)
committerJaroslav Kysela <perex@perex.cz>
Tue, 6 Oct 2015 16:16:46 +0000 (18:16 +0200)
src/descrambler/dvbcam.c
src/input/mpegts/linuxdvb/linuxdvb_en50494.c
src/input/mpegts/linuxdvb/linuxdvb_frontend.c
src/input/mpegts/linuxdvb/linuxdvb_lnb.c
src/input/mpegts/linuxdvb/linuxdvb_private.h
src/input/mpegts/linuxdvb/linuxdvb_satconf.c

index 273997b77b773d587bd1767cde7b685942b08376..3fe0c9a929cd27b288e33629fb3b71e9c788ca4e 100644 (file)
@@ -218,10 +218,10 @@ dvbcam_service_start(service_t *t)
 void
 dvbcam_service_stop(service_t *t)
 {
-       dvbcam_active_service_t *as, *as_tmp;
+  dvbcam_active_service_t *as, *as_tmp;
   linuxdvb_ca_t *ca = NULL;
   dvbcam_active_cam_t *ac2;
-  uint8_t slot;
+  uint8_t slot = -1;
 
   tvhtrace("dvbcam", "stop service %p", t);
 
index ea21380fbaf8230d944314f1f2ee3aa8bd01215e..e33b2a1381c6e396df1b0f41e8959136dce6a6ac 100644 (file)
@@ -184,6 +184,13 @@ linuxdvb_en50494_freq
   return rfreq;
 }
 
+static int
+linuxdvb_en50494_match
+  ( linuxdvb_diseqc_t *ld, dvb_mux_t *lm1, dvb_mux_t *lm2 )
+{
+  return lm1 == lm2;
+}
+
 static int
 linuxdvb_en50494_tune
   ( linuxdvb_diseqc_t *ld, dvb_mux_t *lm,
@@ -321,6 +328,7 @@ linuxdvb_en50494_create0
   le->le_frequency = 0;
   le->le_pin       = LINUXDVB_EN50494_NOPIN;
   le->ld_freq      = linuxdvb_en50494_freq;
+  le->ld_match     = linuxdvb_en50494_match;
 
   ld = linuxdvb_diseqc_create0((linuxdvb_diseqc_t *)le,
                                NULL, &linuxdvb_en50494_class, conf,
index 03b64d61cd362c8b3a41c0ce1ade266eb3000368..fc75e7327f7f00de6dca44a5a74469e48c0ad00b 100644 (file)
@@ -189,6 +189,32 @@ linuxdvb_frontend_dvbs_class_satconf_get ( void *self )
   return &s;
 }
 
+static htsmsg_t *
+linuxdvb_frontend_dvbs_class_master_enum( void * self, const char *lang )
+{
+  linuxdvb_frontend_t *lfe = self, *lfe2;
+  linuxdvb_adapter_t *la;
+  tvh_hardware_t *th;
+  htsmsg_t *m = htsmsg_create_list();
+  htsmsg_t *e = htsmsg_create_map();
+  htsmsg_add_str(e, "key", "");
+  htsmsg_add_str(e, "val", N_("This Tuner"));
+  htsmsg_add_msg(m, NULL, e);
+  LIST_FOREACH(th, &tvh_hardware, th_link) {
+    if (!idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) continue;
+    la = (linuxdvb_adapter_t*)th;
+    LIST_FOREACH(lfe2, &la->la_frontends, lfe_link) {
+      if (lfe2 != lfe && lfe2->lfe_type == lfe->lfe_type) {
+        e = htsmsg_create_map();
+        htsmsg_add_str(e, "key", idnode_uuid_as_sstr(&lfe2->ti_id));
+        htsmsg_add_str(e, "val", lfe2->mi_name);
+        htsmsg_add_msg(m, NULL, e);
+      }
+    }
+  }
+  return m;
+}
+
 const idclass_t linuxdvb_frontend_dvbs_class =
 {
   .ic_super      = &linuxdvb_frontend_class,
@@ -206,6 +232,34 @@ const idclass_t linuxdvb_frontend_dvbs_class =
       .list     = linuxdvb_satconf_type_list,
       .def.s    = "simple"
     },
+    {
+      .type     = PT_STR,
+      .id       = "fe_master",
+      .name     = N_("Master Tuner"),
+      .list     = linuxdvb_frontend_dvbs_class_master_enum,
+      .off      = offsetof(linuxdvb_frontend_t, lfe_master),
+    },
+    {
+      .id       = "networks",
+      .type     = PT_NONE,
+    },
+    {}
+  }
+};
+
+const idclass_t linuxdvb_frontend_dvbs_slave_class =
+{
+  .ic_super      = &linuxdvb_frontend_class,
+  .ic_class      = "linuxdvb_frontend_dvbs",
+  .ic_caption    = N_("Linux DVB-S Slave Frontend"),
+  .ic_properties = (const property_t[]){
+    {
+      .type     = PT_STR,
+      .id       = "fe_master",
+      .name     = N_("Master Tuner"),
+      .list     = linuxdvb_frontend_dvbs_class_master_enum,
+      .off      = offsetof(linuxdvb_frontend_t, lfe_master),
+    },
     {
       .id       = "networks",
       .type     = PT_NONE,
@@ -303,11 +357,37 @@ linuxdvb_frontend_get_grace ( mpegts_input_t *mi, mpegts_mux_t *mm )
 static int
 linuxdvb_frontend_is_enabled ( mpegts_input_t *mi, mpegts_mux_t *mm, int flags )
 {
-  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
+  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi, *lfe2;
+  linuxdvb_adapter_t *la;
+  tvh_hardware_t *th;
+
   if (lfe->lfe_fe_path == NULL) return 0;
   if (!mpegts_input_is_enabled(mi, mm, flags)) return 0;
   if (access(lfe->lfe_fe_path, R_OK | W_OK)) return 0;
   if (lfe->lfe_in_setup) return 0;
+  if (lfe->lfe_type != DVB_TYPE_S) return 0;
+
+  /* check if any "blocking" tuner is running */
+  LIST_FOREACH(th, &tvh_hardware, th_link) {
+    if (!idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) continue;
+    la = (linuxdvb_adapter_t*)th;
+    LIST_FOREACH(lfe2, &la->la_frontends, lfe_link) {
+      if (lfe2 == lfe) continue;
+      if (lfe2->lfe_type != DVB_TYPE_S) continue;
+      if (lfe->lfe_master && !strcmp(lfe->lfe_master, idnode_uuid_as_sstr(&lfe2->ti_id))) {
+        if (lfe2->lfe_satconf == NULL)
+          return 0; /* invalid master */
+        return linuxdvb_satconf_match_mux(lfe2->lfe_satconf, mm);
+      }
+      if (lfe2->lfe_master &&
+          !strcmp(lfe2->lfe_master, idnode_uuid_as_sstr(&lfe->ti_id)) &&
+          lfe2->lfe_refcount > 0) {
+        if (lfe->lfe_satconf == NULL)
+          return 0;
+        return linuxdvb_satconf_match_mux(lfe->lfe_satconf, mm);
+      }
+    }
+  }
   return 1;
 }
 
@@ -316,8 +396,11 @@ linuxdvb_frontend_stop_mux
   ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
 {
   char buf1[256], buf2[256];
-  
-  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
+  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi, *lfe2;
+
+  if (lfe->lfe_master)
+    assert(lfe->lfe_type == DVB_TYPE_S);
+
   mi->mi_display_name(mi, buf1, sizeof(buf1));
   mpegts_mux_nice_name(mmi->mmi_mux, buf2, sizeof(buf2));
   tvhdebug("linuxdvb", "%s - stopping %s", buf1, buf2);
@@ -340,9 +423,31 @@ linuxdvb_frontend_stop_mux
   /* Ensure it won't happen immediately */
   gtimer_arm(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 2);
 
-  if (lfe->lfe_satconf)
+  if (lfe->lfe_satconf && lfe->lfe_refcount == 1)
     linuxdvb_satconf_post_stop_mux(lfe->lfe_satconf);
 
+  if (lfe->lfe_master) {
+    lfe2 = (linuxdvb_frontend_t *)idnode_find(lfe->lfe_master, &linuxdvb_frontend_class, NULL);
+    if (lfe2->lfe_type != lfe->lfe_type)
+      lfe2 = NULL;
+    if (lfe2) { /* master tuner shutdown procedure */
+      assert(lfe2->lfe_refcount >= 0);
+      if (--lfe2->lfe_refcount == 0) {
+        lfe2->lfe_ready   = 0;
+        lfe2->lfe_locked  = 0;
+        lfe2->lfe_status  = 0;
+        lfe2->lfe_status2 = 0;
+        /* Ensure it won't happen immediately */
+        gtimer_arm(&lfe2->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 2);
+        if (lfe2->lfe_satconf)
+          linuxdvb_satconf_post_stop_mux(lfe2->lfe_satconf);
+        lfe2->lfe_in_setup = 0;
+        lfe2->lfe_freq = 0;
+      }
+    }
+  }
+
+  lfe->lfe_refcount--;
   lfe->lfe_in_setup = 0;
   lfe->lfe_freq = 0;
   mpegts_pid_done(&lfe->lfe_pids);
@@ -352,17 +457,47 @@ static int
 linuxdvb_frontend_start_mux
   ( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
 {
-  linuxdvb_frontend_t   *lfe = (linuxdvb_frontend_t*)mi;
-  int res;
+  linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi, *lfe2;
+  int res, f;
+
+  assert(lfe->lfe_in_setup == 0);
 
+  lfe->lfe_refcount++;
   lfe->lfe_in_setup = 1;
   lfe->lfe_ioctls   = 0;
+
+  if (lfe->lfe_master) {
+    assert(lfe->lfe_type == DVB_TYPE_S);
+    lfe2 = (linuxdvb_frontend_t *)idnode_find(lfe->lfe_master, &linuxdvb_frontend_class, NULL);
+    if (lfe2->lfe_type != lfe->lfe_type)
+      lfe2 = NULL;
+    res = SM_CODE_TUNING_FAILED;
+    if (lfe2) {
+      f = linuxdvb_satconf_lnb_freq(lfe2->lfe_satconf, mmi);
+      if (f <= 0)
+        goto end;
+      if (lfe2->lfe_refcount++ == 0) {
+        lfe2->lfe_in_setup = 1;
+        lfe2->lfe_ioctls   = 0;
+        res = linuxdvb_satconf_start_mux(lfe2->lfe_satconf, mmi, 0);
+        if (res)
+          goto end;
+      }
+      res = linuxdvb_frontend_tune1((linuxdvb_frontend_t*)mi, mmi, f);
+    }
+    goto end;
+  }
+
   if (lfe->lfe_satconf)
-    res = linuxdvb_satconf_start_mux(lfe->lfe_satconf, mmi);
+    res = linuxdvb_satconf_start_mux(lfe->lfe_satconf, mmi, lfe->lfe_refcount > 1);
   else
     res = linuxdvb_frontend_tune1((linuxdvb_frontend_t*)mi, mmi, -1);
-  if (res)
+
+end:
+  if (res) {
     lfe->lfe_in_setup = 0;
+    lfe->lfe_refcount--;
+  }
   return res;
 }
 
@@ -459,7 +594,7 @@ linuxdvb_frontend_monitor ( void *aux )
     mmi->mmi_mux->mm_stop(mmi->mmi_mux, 1, SM_CODE_ABORTED);
 
   /* Close FE */
-  if (lfe->lfe_fe_fd > 0 && !mmi && lfe->lfe_powersave) {
+  if (lfe->lfe_fe_fd > 0 && !lfe->lfe_refcount && lfe->lfe_powersave) {
     tvhtrace("linuxdvb", "%s - closing frontend", buf);
     close(lfe->lfe_fe_fd);
     lfe->lfe_fe_fd = -1;
@@ -1116,6 +1251,7 @@ linuxdvb_frontend_clear
 
   /* Open FE */
   lfe->mi_display_name((mpegts_input_t*)lfe, buf1, sizeof(buf1));
+  tvhtrace("linuxdvb", "%s - frontend clear", buf1);
 
   if (lfe->lfe_fe_fd <= 0) {
     lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0);
@@ -1513,11 +1649,19 @@ linuxdvb_frontend_create
     dvb_fe_type_t type, const char *name )
 {
   const idclass_t *idc;
-  const char *str, *uuid = NULL, *scuuid = NULL, *sctype = NULL;
-  char id[12], lname[256];
+  const char *str, *uuid = NULL, *muuid = NULL, *scuuid = NULL, *sctype = NULL;
+  char id[16], lname[256];
   linuxdvb_frontend_t *lfe;
   htsmsg_t *scconf = NULL;
 
+  /* Tuner slave */
+  snprintf(id, sizeof(id), "master for #%d", number);
+  if (conf && type == DVB_TYPE_S) {
+    muuid = htsmsg_get_str(conf, id);
+    if (muuid && uuid && !strcmp(muuid, uuid))
+      muuid = NULL;
+  }
+
   /* Internal config ID */
   snprintf(id, sizeof(id), "%s #%d", dvb_type2str(type), number);
   if (conf)
@@ -1537,7 +1681,8 @@ linuxdvb_frontend_create
 
   /* Class */
   if (type == DVB_TYPE_S)
-    idc = &linuxdvb_frontend_dvbs_class;
+    idc = muuid ? &linuxdvb_frontend_dvbs_slave_class :
+                  &linuxdvb_frontend_dvbs_class;
   else if (type == DVB_TYPE_C)
     idc = &linuxdvb_frontend_dvbc_class;
   else if (type == DVB_TYPE_T)
@@ -1555,7 +1700,8 @@ linuxdvb_frontend_create
   //       in mpegts_input_create()). So we must set early.
   lfe = calloc(1, sizeof(linuxdvb_frontend_t));
   lfe->lfe_number = number;
-  lfe->lfe_type = type;
+  lfe->lfe_type   = type;
+  lfe->lfe_master = muuid ? strdup(muuid) : NULL;
   strncpy(lfe->lfe_name, name, sizeof(lfe->lfe_name));
   lfe->lfe_name[sizeof(lfe->lfe_name)-1] = '\0';
   lfe->lfe_ibuf_size = 18800;
@@ -1598,7 +1744,7 @@ linuxdvb_frontend_create
   mpegts_pid_init(&lfe->lfe_pids);
  
   /* Satconf */
-  if (conf) {
+  if (conf && !muuid) {
     if ((scconf = htsmsg_get_map(conf, "satconf"))) {
       sctype = htsmsg_get_str(scconf, "type");
       scuuid = htsmsg_get_str(scconf, "uuid");
@@ -1606,7 +1752,7 @@ linuxdvb_frontend_create
   }
 
   /* Create satconf */
-  if (lfe->lfe_type == DVB_TYPE_S && !lfe->lfe_satconf)
+  if (lfe->lfe_type == DVB_TYPE_S && !lfe->lfe_satconf && !muuid)
     lfe->lfe_satconf = linuxdvb_satconf_create(lfe, sctype, scuuid, scconf);
 
   /* Double check enabled */
@@ -1618,23 +1764,29 @@ linuxdvb_frontend_create
 void
 linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *fe )
 {
-  char id[12];
+  char id[16];
   htsmsg_t *m = htsmsg_create_map();
 
   /* Save frontend */
   mpegts_input_save((mpegts_input_t*)lfe, m);
   htsmsg_add_str(m, "type", dvb_type2str(lfe->lfe_type));
   htsmsg_add_str(m, "uuid", idnode_uuid_as_sstr(&lfe->ti_id));
-  if (lfe->lfe_satconf) {
+  if (lfe->lfe_satconf && !lfe->lfe_master) {
     htsmsg_t *s = htsmsg_create_map();
     linuxdvb_satconf_save(lfe->lfe_satconf, s);
     htsmsg_add_str(s, "uuid", idnode_uuid_as_sstr(&lfe->lfe_satconf->ls_id));
     htsmsg_add_msg(m, "satconf", s);
   }
+  htsmsg_delete_field(m, "fe_master");
 
   /* Add to list */
   snprintf(id, sizeof(id), "%s #%d", dvb_type2str(lfe->lfe_type), lfe->lfe_number);
   htsmsg_add_msg(fe, id, m);
+
+  if (lfe->lfe_master) {
+    snprintf(id, sizeof(id), "master for #%d", lfe->lfe_number);
+    htsmsg_add_str(fe, id, lfe->lfe_master);
+  }
 }
 
 void
@@ -1659,6 +1811,7 @@ linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
   free(lfe->lfe_fe_path);
   free(lfe->lfe_dmx_path);
   free(lfe->lfe_dvr_path);
+  free(lfe->lfe_master);
 
   /* Delete satconf */
   if (lfe->lfe_satconf)
index 7b095920a05e3218024d75c2178b810959c32dfa..94c50e1378f4b27617a4065135df318923948f06 100644 (file)
@@ -83,6 +83,25 @@ linuxdvb_lnb_standard_freq
   return (uint32_t)abs(f);
 }
 
+static int
+linuxdvb_lnb_standard_match
+  ( linuxdvb_lnb_t *l, dvb_mux_t *lm1, dvb_mux_t *lm2 )
+{
+  linuxdvb_lnb_conf_t *lnb = (linuxdvb_lnb_conf_t*)l;
+  dvb_mux_conf_t      *dmc1 = &lm1->lm_tuning;
+  dvb_mux_conf_t      *dmc2 = &lm2->lm_tuning;
+
+  if (lnb->lnb_switch) {
+    uint32_t hi1 = dmc1->dmc_fe_freq > lnb->lnb_switch;
+    uint32_t hi2 = dmc2->dmc_fe_freq > lnb->lnb_switch;
+    if (hi1 != hi2)
+      return 0;
+  }
+  if (dmc1->u.dmc_fe_qpsk.polarisation != dmc2->u.dmc_fe_qpsk.polarisation)
+    return 0;
+  return 1;
+}
+
 static int
 linuxdvb_lnb_standard_band
   ( linuxdvb_lnb_t *l, dvb_mux_t *lm )
@@ -165,6 +184,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -178,6 +198,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -191,6 +212,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -204,6 +226,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -217,6 +240,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -230,6 +254,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -243,6 +268,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_inverted_pol,
     },
@@ -256,6 +282,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -269,6 +296,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -282,6 +310,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_standard_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_standard_band,
       .lnb_pol    = linuxdvb_lnb_standard_pol,
     },
@@ -295,6 +324,7 @@ struct linuxdvb_lnb_conf linuxdvb_lnb_all[] = {
       .ld_tune    = linuxdvb_lnb_standard_tune,
       },
       .lnb_freq   = linuxdvb_lnb_bandstack_freq,
+      .lnb_match  = linuxdvb_lnb_standard_match,
       .lnb_band   = linuxdvb_lnb_bandstack_band,
       .lnb_pol    = linuxdvb_lnb_bandstack_pol,
     },
index 07935360662ddf06271cd0c674a4deb1fc389642..cc7e98f4e0637e207412b30b82620f1e9f7d2af9 100644 (file)
@@ -68,6 +68,8 @@ typedef TAILQ_HEAD(linuxdvb_satconf_ele_list,linuxdvb_satconf_ele) linuxdvb_satc
 typedef TAILQ_HEAD(linuxdvb_ca_capmt_queue,linuxdvb_ca_capmt) linuxdvb_ca_capmt_queue_t;
 #endif
 
+extern const idclass_t linuxdvb_adapter_class;
+
 struct linuxdvb_adapter
 {
   tvh_hardware_t;
@@ -131,6 +133,7 @@ struct linuxdvb_frontend
   /*
    * Tuning
    */
+  int                       lfe_refcount;
   int                       lfe_ready;
   int                       lfe_in_setup;
   int                       lfe_locked;
@@ -146,6 +149,7 @@ struct linuxdvb_frontend
   /*
    * Configuration
    */
+  char                     *lfe_master;
   int                       lfe_powersave;
   int                       lfe_tune_repeats;
   uint32_t                  lfe_skip_bytes;
@@ -310,6 +314,7 @@ struct linuxdvb_diseqc
   linuxdvb_satconf_ele_t   *ld_satconf;
   int (*ld_grace) (linuxdvb_diseqc_t *ld, dvb_mux_t *lm);
   int (*ld_freq)  (linuxdvb_diseqc_t *ld, dvb_mux_t *lm, int freq);
+  int (*ld_match) (linuxdvb_diseqc_t *ld, dvb_mux_t *lm1, dvb_mux_t *lm2);
   int (*ld_tune)  (linuxdvb_diseqc_t *ld, dvb_mux_t *lm,
                    linuxdvb_satconf_t *lsp, linuxdvb_satconf_ele_t *ls,
                    int vol, int pol, int band, int freq);
@@ -320,9 +325,10 @@ struct linuxdvb_diseqc
 struct linuxdvb_lnb
 {
   linuxdvb_diseqc_t;
-  uint32_t  (*lnb_freq)(linuxdvb_lnb_t*, dvb_mux_t*);
-  int       (*lnb_band)(linuxdvb_lnb_t*, dvb_mux_t*);
-  int       (*lnb_pol) (linuxdvb_lnb_t*, dvb_mux_t*);
+  uint32_t  (*lnb_freq) (linuxdvb_lnb_t*, dvb_mux_t*);
+  int       (*lnb_match)(linuxdvb_lnb_t*, dvb_mux_t*, dvb_mux_t*);
+  int       (*lnb_band) (linuxdvb_lnb_t*, dvb_mux_t*);
+  int       (*lnb_pol)  (linuxdvb_lnb_t*, dvb_mux_t*);
 };
 
 struct linuxdvb_en50494
@@ -455,11 +461,17 @@ int linuxdvb_satconf_get_priority
 
 int linuxdvb_satconf_get_grace
   ( linuxdvb_satconf_t *ls, mpegts_mux_t *mm );
-  
+
+int linuxdvb_satconf_lnb_freq
+  ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi );
+
 void linuxdvb_satconf_post_stop_mux( linuxdvb_satconf_t *ls );
 
 int linuxdvb_satconf_start_mux
-  ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi );
+  ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi, int skip_diseqc );
+
+int linuxdvb_satconf_match_mux
+  ( linuxdvb_satconf_t *ls, mpegts_mux_t *mm );
 
 int linuxdvb_satconf_start ( linuxdvb_satconf_t *ls, int delay, int vol );
 
index 157be159d2f9e7987abb8c36109429a81697a482..7751d0460795f311a8f3e8c0817edb1816a6ca97 100644 (file)
@@ -665,6 +665,7 @@ void
 linuxdvb_satconf_post_stop_mux
   ( linuxdvb_satconf_t *ls )
 {
+  ls->ls_mmi = NULL;
   gtimer_disarm(&ls->ls_diseqc_timer);
   if (ls->ls_frontend && ls->ls_lnb_poweroff) {
     linuxdvb_diseqc_set_volt(ls, -1);
@@ -825,14 +826,39 @@ linuxdvb_satconf_ele_tune_cb ( void *o )
 }
 
 int
-linuxdvb_satconf_start_mux
+linuxdvb_satconf_lnb_freq
   ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi )
+{
+  int f;
+  linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_find_ele(ls, mmi->mmi_mux);
+  dvb_mux_t              *lm  = (dvb_mux_t*)mmi->mmi_mux;
+
+  if (!lse->lse_lnb)
+    return -1;
+
+  f = lse->lse_lnb->lnb_freq(lse->lse_lnb, lm);
+  if (f == (uint32_t)-1)
+    return -1;
+
+  /* calculate tuning frequency for en50494 */
+  if (lse->lse_en50494) {
+    f = lse->lse_en50494->ld_freq(lse->lse_en50494, lm, f);
+    if (f < 0) {
+      tvherror("en50494", "invalid tuning freq");
+      return -1;
+    }
+  }
+  return f;
+}
+
+int
+linuxdvb_satconf_start_mux
+  ( linuxdvb_satconf_t *ls, mpegts_mux_instance_t *mmi, int skip_diseqc )
 {
   int r;
   uint32_t f;
   linuxdvb_satconf_ele_t *lse = linuxdvb_satconf_find_ele(ls, mmi->mmi_mux);
   linuxdvb_frontend_t    *lfe = (linuxdvb_frontend_t*)ls->ls_frontend;
-  dvb_mux_t              *lm  = (dvb_mux_t*)mmi->mmi_mux;
 
   /* Not fully configured */
   if (!lse) return SM_CODE_TUNING_FAILED;
@@ -845,23 +871,16 @@ linuxdvb_satconf_start_mux
   if (!lse->lse_lnb)
     return SM_CODE_TUNING_FAILED;
 
+  if (skip_diseqc) {
+    f = linuxdvb_satconf_lnb_freq(ls, mmi);
+    if (f < 0)
+      return SM_CODE_TUNING_FAILED;
+    return linuxdvb_frontend_tune1(lfe, mmi, f);
+  }
   if (ls->ls_early_tune) {
-
-    f = lse->lse_lnb->lnb_freq(lse->lse_lnb, lm);
-    if (f == (uint32_t)-1)
+    f = linuxdvb_satconf_lnb_freq(ls, mmi);
+    if (f < 0)
       return SM_CODE_TUNING_FAILED;
-
-    /* calculate tuning frequency for en50494 */
-    if (lse->lse_en50494) {
-      r = lse->lse_en50494->ld_freq(lse->lse_en50494, lm, f);
-      if (r < 0) {
-        tvherror("en50494", "invalid tuning freq");
-        return -1;
-      }
-      /* tune frequency for the frontend */
-      f = r;
-    }
-
     r = linuxdvb_frontend_tune0(lfe, mmi, f);
     if (r) return r;
   } else {
@@ -889,6 +908,47 @@ linuxdvb_satconf_reset
   ls->ls_last_tone_off = 0;
 }
 
+/*
+ * return 0 if passed mux cannot be used simultanously with given
+ * diseqc config
+ */
+int
+linuxdvb_satconf_match_mux
+  ( linuxdvb_satconf_t *ls, mpegts_mux_t *mm )
+{
+  mpegts_mux_instance_t *mmi = ls->ls_mmi;
+
+  if (mmi == NULL || mmi->mmi_mux == NULL)
+    return 1;
+
+  linuxdvb_satconf_ele_t *lse1 = linuxdvb_satconf_find_ele(ls, mm);
+  linuxdvb_satconf_ele_t *lse2 = linuxdvb_satconf_find_ele(ls, mmi->mmi_mux);
+  dvb_mux_t *lm1 = (dvb_mux_t*)mmi->mmi_mux;
+  dvb_mux_t *lm2 = (dvb_mux_t*)mm;
+
+#if ENABLE_TRACE
+  char buf1[256], buf2[256];
+  dvb_mux_conf_str(&lm1->lm_tuning, buf1, sizeof(buf1));
+  dvb_mux_conf_str(&lm2->lm_tuning, buf2, sizeof(buf2));
+  tvhtrace("diseqc", "match mux 1 - %s", buf1);
+  tvhtrace("diseqc", "match mux 2 - %s", buf2);
+#endif
+
+  if (lse1 != lse2) {
+    tvhtrace("diseqc", "match position failed");
+    return 0;
+  }
+  if (!lse1->lse_lnb->lnb_match(lse1->lse_lnb, lm1, lm2)) {
+    tvhtrace("diseqc", "match LNB failed");
+    return 0;
+  }
+  if (lse1->lse_en50494 && !lse1->lse_en50494->ld_match(lse1->lse_en50494, lm1, lm2)) {
+    tvhtrace("diseqc", "match en50494 failed");
+    return 0;
+  }
+  return 1;
+}
+
 /* **************************************************************************
  * Create/Delete satconf
  * *************************************************************************/