]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
linuxdvb_ca: add gui and configurable options
authorDamjan Marion <damarion@cisco.com>
Fri, 1 May 2015 17:58:32 +0000 (19:58 +0200)
committerJaroslav Kysela <perex@perex.cz>
Sat, 2 May 2015 16:39:43 +0000 (18:39 +0200)
src/input/mpegts/linuxdvb/linuxdvb_adapter.c
src/input/mpegts/linuxdvb/linuxdvb_ca.c
src/input/mpegts/linuxdvb/linuxdvb_private.h
src/webui/static/app/idnode.js

index 843809395ca864263fb5e637a0e70fc2978c96e6..db3e13d25c7fd728728aa579be10c6e171153e65 100644 (file)
@@ -56,10 +56,17 @@ static idnode_set_t *
 linuxdvb_adapter_class_get_childs ( idnode_t *in )
 {
   linuxdvb_frontend_t *lfe;
+#if ENABLE_LINUXDVB_CA
+  linuxdvb_ca_t *lca;
+#endif
   linuxdvb_adapter_t *la = (linuxdvb_adapter_t*)in;
   idnode_set_t *is = idnode_set_create(0);
   LIST_FOREACH(lfe, &la->la_frontends, lfe_link)
     idnode_set_add(is, &lfe->ti_id, NULL);
+#if ENABLE_LINUXDVB_CA
+  LIST_FOREACH(lca, &la->la_ca_devices, lca_link)
+    idnode_set_add(is, &lca->lca_id, NULL);
+#endif
   return is;
 }
 
@@ -98,6 +105,9 @@ linuxdvb_adapter_save ( linuxdvb_adapter_t *la )
 {
   htsmsg_t *m, *l;
   linuxdvb_frontend_t *lfe;
+#if ENABLE_LINUXDVB_CA
+  linuxdvb_ca_t *lca;
+#endif
 
   m = htsmsg_create_map();
   idnode_save(&la->th_id, m);
@@ -108,6 +118,14 @@ linuxdvb_adapter_save ( linuxdvb_adapter_t *la )
     linuxdvb_frontend_save(lfe, l);
   htsmsg_add_msg(m, "frontends", l);
 
+  /* CAs */
+#if ENABLE_LINUXDVB_CA
+  l = htsmsg_create_map();
+  LIST_FOREACH(lca, &la->la_ca_devices, lca_link)
+    linuxdvb_ca_save(lca, l);
+  htsmsg_add_msg(m, "ca_devices", l);
+#endif
+
   /* Save */
   hts_settings_save(m, "input/linuxdvb/adapters/%s",
                     idnode_uuid_as_str(&la->th_id));
@@ -229,6 +247,7 @@ linuxdvb_adapter_add ( const char *path )
   char fe_path[512], dmx_path[512], dvr_path[512];
 #if ENABLE_LINUXDVB_CA
   char ca_path[512];
+  htsmsg_t *caconf = NULL;
 #endif
   tvh_uuid_t uuid;
   linuxdvb_adapter_t *la = NULL;
@@ -387,7 +406,11 @@ linuxdvb_adapter_add ( const char *path )
       continue;
 
     pthread_mutex_lock(&global_lock);
-    linuxdvb_ca_create(la, i, ca_path);
+
+    if (conf)
+      caconf = htsmsg_get_map(conf, "ca_devices");
+
+    linuxdvb_ca_create(caconf, la, i, ca_path);
     pthread_mutex_unlock(&global_lock);
   }
 #endif
index b04847033a393bf4a77f58d68362c4c61784ed25..150f638b31129ec2ef5e459b395aa0b3c645528d 100644 (file)
@@ -46,13 +46,98 @@ const static char *
 ca_slot_state2str(ca_slot_state_t v)
 {
   switch(v) {
-    case CA_SLOT_STATE_EMPTY:           return "EMPTY";
-    case CA_SLOT_STATE_MODULE_PRESENT:  return "MODULE_PRESENT";
-    case CA_SLOT_STATE_MODULE_READY:    return "MODULE_READY";
+    case CA_SLOT_STATE_EMPTY:           return "slot empty";
+    case CA_SLOT_STATE_MODULE_PRESENT:  return "module present";
+    case CA_SLOT_STATE_MODULE_READY:    return "module ready";
        };
   return "UNKNOWN";
 }
 
+static void
+linuxdvb_ca_class_save ( idnode_t *in )
+{
+  linuxdvb_adapter_t *la = ((linuxdvb_ca_t*)in)->lca_adapter;
+  linuxdvb_adapter_save(la);
+}
+
+static void
+linuxdvb_ca_class_enabled_notify ( void *p )
+{
+  linuxdvb_ca_t *lca = (linuxdvb_ca_t *) p;
+
+  if (lca->lca_enabled) {
+    if (lca->lca_ca_fd < 0) {
+      lca->lca_ca_fd = tvh_open(lca->lca_ca_path, O_RDWR | O_NONBLOCK, 0);
+      tvhtrace("linuxdvb", "opening ca%u %s (fd %d)",
+               lca->lca_number, lca->lca_ca_path, lca->lca_ca_fd);
+    }
+  } else {
+    tvhtrace("linuxdvb", "closing ca%u %s (fd %d)",
+             lca->lca_number, lca->lca_ca_path, lca->lca_ca_fd);
+
+    if (lca->lca_en50221_thread_running) {
+      lca->lca_en50221_thread_running = 0;
+      pthread_join(lca->lca_en50221_thread, NULL);
+    }
+
+    ioctl(lca->lca_ca_fd, CA_RESET, NULL);
+
+    close(lca->lca_ca_fd);
+    lca->lca_ca_fd = -1;
+
+    idnode_notify_title_changed(&lca->lca_id);
+  }
+}
+
+static const char *
+linuxdvb_ca_class_get_title ( idnode_t *in )
+{
+  linuxdvb_ca_t *lca = (linuxdvb_ca_t *) in;
+  static char buf[256];
+  if (!lca->lca_enabled)
+    snprintf(buf, sizeof(buf), "ca%u: disabled", lca->lca_number);
+  else if (lca->lca_state == CA_SLOT_STATE_EMPTY)
+    snprintf(buf, sizeof(buf), "ca%u: slot empty", lca->lca_number);
+  else
+    snprintf(buf, sizeof(buf), "ca%u: %s (%s)", lca->lca_number,
+           lca->lca_cam_menu_string, lca->lca_state_str);
+
+  return buf;
+}
+
+const idclass_t linuxdvb_ca_class =
+{
+  .ic_class      = "linuxdvb_ca",
+  .ic_caption    = "Linux DVB CA",
+  .ic_save       = linuxdvb_ca_class_save,
+  .ic_get_title   = linuxdvb_ca_class_get_title,
+  .ic_properties = (const property_t[]) {
+    {
+      .type     = PT_BOOL,
+      .id       = "enabled",
+      .name     = "Enabled",
+      .off      = offsetof(linuxdvb_ca_t, lca_enabled),
+      .notify   = linuxdvb_ca_class_enabled_notify,
+    },
+    {
+      .type     = PT_STR,
+      .id       = "ca_path",
+      .name     = "Device Path",
+      .opts     = PO_RDONLY | PO_NOSAVE,
+      .off      = offsetof(linuxdvb_ca_t, lca_ca_path),
+    },
+    {
+      .type     = PT_STR,
+      .id       = "slot_state",
+      .name     = "Slot State",
+      .opts     = PO_RDONLY | PO_NOSAVE,
+      .off      = offsetof(linuxdvb_ca_t, lca_state_str),
+    },
+    {}
+  }
+};
+
+
 static uint32_t
 resource_ids[] = { EN50221_APP_RM_RESOURCEID,
                    EN50221_APP_MMI_RESOURCEID,
@@ -122,8 +207,10 @@ linuxdvb_ca_session_cb (void *arg, int reason, uint8_t slot_id,
       }
                        break;
     case S_SCALLBACK_REASON_CLOSE:
-      if (rid == EN50221_APP_CA_RESOURCEID)
+      if (rid == EN50221_APP_CA_RESOURCEID) {
         dvbcam_unregister_cam(lca, 0);
+        lca->lca_cam_menu_string[0] = 0;
+      }
       break;
     case S_SCALLBACK_REASON_TC_CONNECT:
       break;
@@ -205,12 +292,20 @@ linuxdvb_ca_ai_callback(void *arg, uint8_t slot_id, uint16_t session_num,
                      uint16_t manufacturer_code, uint8_t menu_string_len,
                      uint8_t *menu_string)
 {
+    linuxdvb_ca_t * lca = arg;
+
     tvhinfo("en50221", "CAM slot %u: Application type: %02x, manufacturer: %04x,"
             " Manufacturer code: %04x", slot_id, app_type, app_manufacturer,
             manufacturer_code);
 
     tvhinfo("en50221", "CAM slot %u: Menu string: %.*s", slot_id,
             menu_string_len, menu_string);
+
+    snprintf(lca->lca_cam_menu_string, sizeof(lca->lca_cam_menu_string),
+             "%.*s", menu_string_len, menu_string);
+
+    idnode_notify_title_changed(&lca->lca_id);
+
     return 0;
 }
 
@@ -450,7 +545,7 @@ linuxdvb_ca_monitor ( void *aux )
 
   csi.num = 0;
 
-  if (lca->lca_ca_fd > 0) {
+  if (lca->lca_ca_fd >= 0) {
     if ((ioctl(lca->lca_ca_fd, CA_GET_SLOT_INFO, &csi)) != 0) {
       tvherror("linuxdvb", "failed to get CAM slot %u info [e=%s]",
                csi.num, strerror(errno));
@@ -462,21 +557,28 @@ linuxdvb_ca_monitor ( void *aux )
     else
       state = CA_SLOT_STATE_EMPTY;
 
+    lca->lca_state_str = ca_slot_state2str(state);
+
     if (lca->lca_state != state) {
       tvhlog(LOG_INFO, "linuxdvb", "CAM slot %u status changed to %s",
-             csi.num, ca_slot_state2str(state));
-
-      if (state == CA_SLOT_STATE_MODULE_READY) {
-       lca->lca_en50221_thread_running = 1;
-        tvhthread_create(&lca->lca_en50221_thread, NULL,
-                         linuxdvb_ca_en50221_thread, lca);
-      } else if (lca->lca_en50221_thread_running) {
-        lca->lca_en50221_thread_running = 0;
-        pthread_join(lca->lca_en50221_thread, NULL);
-      }
-
+             csi.num, lca->lca_state_str);
+      idnode_notify_title_changed(&lca->lca_id);
       lca->lca_state = state;
     }
+
+    if ((!lca->lca_en50221_thread_running) &&
+        (state == CA_SLOT_STATE_MODULE_READY)) 
+    {
+      lca->lca_en50221_thread_running = 1;
+      tvhthread_create(&lca->lca_en50221_thread, NULL,
+                       linuxdvb_ca_en50221_thread, lca);
+    } else if (lca->lca_en50221_thread_running &&
+               (state != CA_SLOT_STATE_MODULE_READY))
+    {
+      lca->lca_en50221_thread_running = 0;
+      pthread_join(lca->lca_en50221_thread, NULL);
+    }
+
   }
 
   gtimer_arm_ms(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, 250);
@@ -484,25 +586,37 @@ linuxdvb_ca_monitor ( void *aux )
 
 linuxdvb_ca_t *
 linuxdvb_ca_create
-  ( linuxdvb_adapter_t *la, int number, const char *ca_path)
+  ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path)
 {
-       linuxdvb_ca_t *lca;
-       char id[6];
-
-  /* Internal config ID */
-  snprintf(id, sizeof(id), "CA #%d", number);
+  linuxdvb_ca_t *lca;
+  char id[6];
+  const char *uuid = NULL;
 
-       lca = calloc(1, sizeof(linuxdvb_frontend_t));
+  lca = calloc(1, sizeof(linuxdvb_ca_t));
+  memset(lca, 0, sizeof(linuxdvb_ca_t));
   lca->lca_number = number;
   lca->lca_ca_path  = strdup(ca_path);
+  lca->lca_ca_fd = -1;
+
+  /* Internal config ID */
+  snprintf(id, sizeof(id), "ca%u", number);
+
+  if (conf)
+    conf = htsmsg_get_map(conf, id);
+  if (conf)
+    uuid = htsmsg_get_str(conf, "uuid");
+
+  if (idnode_insert(&lca->lca_id, uuid, &linuxdvb_ca_class, 0)) {
+    free(lca);
+    return NULL;
+  }
+
+  if (conf)
+    idnode_load(&lca->lca_id, conf);
 
   /* Adapter link */
   lca->lca_adapter = la;
-  LIST_INSERT_HEAD(&la->la_cas, lca, lca_link);
-
-  lca->lca_ca_fd = tvh_open(lca->lca_ca_path, O_RDWR | O_NONBLOCK, 0);
-    tvhtrace("linuxdvb", "opening CA%u %s (fd %d)",
-             lca->lca_number, lca->lca_ca_path, lca->lca_ca_fd);
+  LIST_INSERT_HEAD(&la->la_ca_devices, lca, lca_link);
 
   gtimer_arm_ms(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, 250);
 
@@ -562,3 +676,17 @@ linuxdvb_ca_send_capmt(linuxdvb_ca_t *lca, uint8_t slot, const uint8_t *ptr, int
 fail:
   free(buffer);
 }
+
+void linuxdvb_ca_save( linuxdvb_ca_t *lca, htsmsg_t *msg )
+{
+  char id[8];
+  htsmsg_t *m = htsmsg_create_map();
+
+  htsmsg_add_str(m, "uuid", idnode_uuid_as_str(&lca->lca_id));
+  idnode_save(&lca->lca_id, m);
+
+  /* Add to list */
+  snprintf(id, sizeof(id), "ca%u", lca->lca_number);
+  htsmsg_add_msg(msg, id, m);
+
+}
index 0522d15f55a2812812a9277bd8e5783004ded7df..b3f2c49a9c915a2d7206cdd13458b5505999ff17 100644 (file)
@@ -84,7 +84,7 @@ struct linuxdvb_adapter
    *  CA devices
    */
 #if ENABLE_LINUXDVB_CA
-  LIST_HEAD(,linuxdvb_ca) la_cas;
+  LIST_HEAD(,linuxdvb_ca) la_ca_devices;
 #endif
   /*
   * Functions
@@ -158,6 +158,7 @@ struct linuxdvb_frontend
 #if ENABLE_LINUXDVB_CA
 struct linuxdvb_ca
 {
+  idnode_t                     lca_id;
   /*
    * Adapter
    */
@@ -168,6 +169,7 @@ struct linuxdvb_ca
    * CA handling
    */
   int                       lca_ca_fd;
+  int                       lca_enabled;
   gtimer_t                  lca_monitor_timer;
   pthread_t                 lca_en50221_thread;
   int                       lca_en50221_thread_running;
@@ -194,6 +196,11 @@ struct linuxdvb_ca
   char                     lca_name[128];
   char                     *lca_ca_path;
   int                      lca_state;
+  const char               *lca_state_str;
+  /*
+   * CAM module info
+   */
+  char                     lca_cam_menu_string[64];
 };
 #endif
 
@@ -357,7 +364,9 @@ int linuxdvb2tvh_delsys ( int delsys );
 
 linuxdvb_ca_t *
 linuxdvb_ca_create
-  ( linuxdvb_adapter_t *la, int number, const char *ca_path);
+  ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path);
+
+void linuxdvb_ca_save( linuxdvb_ca_t *lca, htsmsg_t *m );
 
 void
 linuxdvb_ca_send_capmt(linuxdvb_ca_t *lca, uint8_t slot, const uint8_t *ptr, int len);
index 4b01a74c7c9d34caa7d40e1d43b711c714f02fc5..7c41ddb66bec057bb48adbe2d83a377335979483 100644 (file)
@@ -1913,6 +1913,7 @@ tvheadend.idnode_tree = function(panel, conf)
             if (o.text)
                 n.setText(o.text);
             tree.getRootNode().reload();
+            tree.expandAll();
             // cannot get this to properly reload children and maintain state
         }
     }