Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
linuxdvb_ca: add gui and configurable options
  • Loading branch information
dmarion authored and perexg committed May 2, 2015
1 parent 9273680 commit 70bd335
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 31 deletions.
25 changes: 24 additions & 1 deletion src/input/mpegts/linuxdvb/linuxdvb_adapter.c
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
184 changes: 156 additions & 28 deletions src/input/mpegts/linuxdvb/linuxdvb_ca.c
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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));
Expand All @@ -462,47 +557,66 @@ 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);
}

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);

Expand Down Expand Up @@ -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);

}
13 changes: 11 additions & 2 deletions src/input/mpegts/linuxdvb/linuxdvb_private.h
Expand Up @@ -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
Expand Down Expand Up @@ -158,6 +158,7 @@ struct linuxdvb_frontend
#if ENABLE_LINUXDVB_CA
struct linuxdvb_ca
{
idnode_t lca_id;
/*
* Adapter
*/
Expand All @@ -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;
Expand All @@ -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

Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/webui/static/app/idnode.js
Expand Up @@ -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
}
}
Expand Down

0 comments on commit 70bd335

Please sign in to comment.