From: Jasmin Jessich Date: Sun, 12 Nov 2017 16:50:33 +0000 (+0100) Subject: Added DDCI detection and creation X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=28fd923a42dcdedbd8e17849cf5a69a8623459a9;p=thirdparty%2Ftvheadend.git Added DDCI detection and creation - Check if a device ciX or secX exists. - Create also the DD CI structure, if one of the ci pathes have been found. - Open and close the DD CI in linuxdvb_ca_class_enabled_notify. Signed-off-by: Jasmin Jessich --- diff --git a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c index f13d70c03..e13784fe3 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_adapter.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_adapter.c @@ -40,6 +40,10 @@ #define CA_PATH "%s/ca%d" #define DVR_PATH "%s/dvr%d" #define DMX_PATH "%s/demux%d" +#define CI_PATH "%s/ci%d" +#define SEC_PATH "%s/sec%d" + +#define MAX_DEV_OPEN_ATTEMPTS 20 /* *************************************************************************** * DVB Adapter @@ -299,19 +303,55 @@ linuxdvb_get_systems(int fd, struct dtv_property *_cmd) } #endif +#if ENABLE_DDCI +/* ret: 0 .. DDCI found and usable + * -1 .. DDCI found but not usable + * -2 .. DDCI not found + */ +static int +linuxdvb_check_ddci ( const char *ci_path ) +{ + int j, fd, ret = -2; + + tvhtrace(LS_DDCI, "checking for DDCI %s", ci_path); + + /* check existence */ + if (!access(ci_path, R_OK | W_OK)) { + for (j = 0; j < MAX_DEV_OPEN_ATTEMPTS; j++) { + if ((fd = tvh_open(ci_path, O_WRONLY, 0)) >= 0) break; + tvh_safe_usleep(100000); + } + if (fd >= 0) { + close(fd); + tvhinfo(LS_DDCI, "DDCI found %s", ci_path); + ret = 0; + } + else { + ret = -1; + tvherror(LS_DDCI, "unable to open %s", ci_path); + } + } + return ret; +} +#endif /* ENABLE_DDCI */ + /* * Add adapter by path */ static void linuxdvb_adapter_add ( const char *path ) { -#define MAX_DEV_OPEN_ATTEMPTS 20 extern int linuxdvb_adapter_mask; int a, i, j, r, fd; char fe_path[512], dmx_path[512], dvr_path[512], name[132]; #if ENABLE_LINUXDVB_CA char ca_path[512]; htsmsg_t *caconf = NULL; + const char *ci_found = NULL; +#if ENABLE_DDCI + linuxdvb_adapter_t *la_fe = NULL; + char ci_path[512]; +#endif #endif linuxdvb_adapter_t *la = NULL; struct dvb_frontend_info dfi; @@ -325,6 +365,8 @@ linuxdvb_adapter_add ( const char *path ) linuxdvb_frontend_t *lfe; #endif + tvhtrace(LS_LINUXDVB, "scanning adapter %s", path); + /* Validate the path */ if (sscanf(path, "/dev/dvb/adapter%d", &a) != 1) return; @@ -437,6 +479,36 @@ linuxdvb_adapter_add ( const char *path ) /* Process each CA device */ #if ENABLE_LINUXDVB_CA + /* A normal DVB card with hard wired CI interface creates the caX device in + * the same adapter directory than the frontendX device. + * The Digital Device CI interfaces do the same, when the driver is started + * with adapter_alloc=3. This parameter is used together with the redirect + * feature of the DD CI to inform user mode applications, that the caX device + * is hard wired to the DVB tuner. This means the special DDCI feature must + * not be activated, when the caX and the frontedX device are present in the + * same adapter directory. + * + * The normal use case for the DD CI is a stand alone CI interface, which can + * be used by any tuner in the system, which is not limited to Digital Devices + * hardware. + * This is the default mode of the driver or started with adapter_alloc=0 + * parameter. In this mode the caX device is created in a dedicated adapter + * directory. + * + * In both modes also a secX or ciX device is create additionally. In the + * first mode (adapter_alloc=3 and redirect) this shall be ignored. In the + * second mode it needs to be associated with the caX device and later on + * used to send/receive the crypted/decrypted TS stream to/from the CAM. + * + */ + +#if ENABLE_DDCI + /* remember, if la exists already, which means DD CI is hard wired to the + * tuner + */ + la_fe = la; +#endif + for (i = 0; i < 32; i++) { snprintf(ca_path, sizeof(ca_path), CA_PATH, path, i); if (access(ca_path, R_OK | W_OK)) continue; @@ -457,6 +529,34 @@ linuxdvb_adapter_add ( const char *path ) continue; } +#if ENABLE_DDCI + /* check for DD CI only, if no frontend was found (stand alone mode) */ + if (!la_fe) { + int ddci_ret; + + /* DD driver uses ciX */ + snprintf(ci_path, sizeof(ci_path), CI_PATH, path, i); + ddci_ret = linuxdvb_check_ddci ( ci_path ); + if (ddci_ret == -2 ) { + /* Mainline driver uses secX */ + snprintf(ci_path, sizeof(ci_path), SEC_PATH, path, i); + ddci_ret = linuxdvb_check_ddci ( ci_path ); + } + + /* The DD CI device have not been found, or was not usable, so we + * ignore the whole caX device also, because we are in DD CI stand alone + * mode and this requires a working ciX/secX device. + * It would be possible to check for -1 so that it get ignored only in + * case of an open error. + */ + if (ddci_ret) { + tvherror(LS_LINUXDVB, "ignoring DDCI %s", ca_path); + continue; + } + ci_found = ci_path; + } +#endif /* ENABLE_DDCI */ + pthread_mutex_lock(&global_lock); if (!la) { @@ -471,10 +571,10 @@ linuxdvb_adapter_add ( const char *path ) if (conf) caconf = htsmsg_get_map(conf, "ca_devices"); - linuxdvb_ca_create(caconf, la, i, ca_path); + linuxdvb_ca_create(caconf, la, i, ca_path, ci_found); pthread_mutex_unlock(&global_lock); } -#endif +#endif /* ENABLE_LINUXDVB_CA */ /* Cleanup */ if (conf) diff --git a/src/input/mpegts/linuxdvb/linuxdvb_ca.c b/src/input/mpegts/linuxdvb/linuxdvb_ca.c index b941d3dae..3382aba69 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_ca.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_ca.c @@ -130,8 +130,13 @@ linuxdvb_ca_class_enabled_notify ( void *p, const char *lang ) lca->lca_ca_fd = tvh_open(lca->lca_ca_path, O_RDWR | O_NONBLOCK, 0); tvhtrace(LS_LINUXDVB, "opening ca%u %s (fd %d)", lca->lca_number, lca->lca_ca_path, lca->lca_ca_fd); - if (lca->lca_ca_fd >= 0) + if (lca->lca_ca_fd >= 0) { +#if ENABLE_DDCI + if (lca->lddci) + linuxdvb_ddci_open(lca->lddci); +#endif mtimer_arm_rel(&lca->lca_monitor_timer, linuxdvb_ca_monitor, lca, ms2mono(250)); + } } } else { tvhtrace(LS_LINUXDVB, "closing ca%u %s (fd %d)", @@ -151,6 +156,10 @@ linuxdvb_ca_class_enabled_notify ( void *p, const char *lang ) close(lca->lca_ca_fd); lca->lca_ca_fd = -1; +#if ENABLE_DDCI + if (lca->lddci) + linuxdvb_ddci_close(lca->lddci); +#endif } idnode_notify_title_changed(&lca->lca_id, lang); @@ -790,7 +799,8 @@ linuxdvb_ca_monitor ( void *aux ) linuxdvb_ca_t * linuxdvb_ca_create - ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path) + ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path, + const char *ci_path) { linuxdvb_ca_t *lca; char id[6]; @@ -804,6 +814,11 @@ linuxdvb_ca_create lca->lca_capmt_interval = 100; lca->lca_capmt_query_interval = 1200; +#if ENABLE_DDCI + if (ci_path) + lca->lddci = linuxdvb_ddci_create(lca, ci_path); +#endif + /* Internal config ID */ snprintf(id, sizeof(id), "ca%u", number); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_private.h b/src/input/mpegts/linuxdvb/linuxdvb_private.h index ee9d7bbb0..efbc7be1a 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_private.h +++ b/src/input/mpegts/linuxdvb/linuxdvb_private.h @@ -435,7 +435,8 @@ int linuxdvb2tvh_delsys ( int delsys ); linuxdvb_ca_t * linuxdvb_ca_create - ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path); + ( htsmsg_t *conf, linuxdvb_adapter_t *la, int number, const char *ca_path, + const char *ci_path ); void linuxdvb_ca_save( linuxdvb_ca_t *lca, htsmsg_t *m );