diff -urN tvheadend-4.2.2.old/src/input/mpegts/linuxdvb/linuxdvb_ca.c tvheadend-4.2.2/src/input/mpegts/linuxdvb/linuxdvb_ca.c --- tvheadend-4.2.2.old/src/input/mpegts/linuxdvb/linuxdvb_ca.c 2017-05-16 11:15:24.000000000 +0000 +++ tvheadend-4.2.2/src/input/mpegts/linuxdvb/linuxdvb_ca.c 2017-06-09 22:39:44.856427300 +0000 @@ -37,6 +37,9 @@ #include "descrambler/caid.h" #include "descrambler/dvbcam.h" +/* Seconds to wait for a slot to become ready */ +#define MAX_SLOT_READY_WAIT_SECS 10 + typedef enum { CA_SLOT_STATE_EMPTY = 0, CA_SLOT_STATE_MODULE_PRESENT, @@ -666,6 +669,8 @@ { linuxdvb_ca_t *lca = aux; int slot_id, lasterror = 0; + int i; + ca_slot_info_t csi; lca->lca_tl = en50221_tl_create(5, 32); if (!lca->lca_tl) { @@ -673,6 +678,39 @@ return NULL; } + /* Fix - Step 1: Issue a reset of the slot */ + if (ioctl(lca->lca_ca_fd, CA_RESET, (1 << lca->lca_number))) { + tvherror(LS_EN50221, "unable to reset ca%u %s", + lca->lca_number, lca->lca_ca_path); + return NULL; + } + + /* Fix - Step 2: Poll the slot until it becomes ready */ + csi.num = lca->lca_number; + for (i=0; i <= (MAX_SLOT_READY_WAIT_SECS * 1000); i++) { + /* sleep 1ms */ + tvh_safe_usleep(1000); + /* get slot information */ + if(ioctl(lca->lca_ca_fd, CA_GET_SLOT_INFO, &csi)) { + tvherror(LS_EN50221, "unable to get slot info for CAM #%d, path: %s", + lca->lca_number, lca->lca_ca_path); + return NULL; + } + /* check for slot being ready */ + if(csi.flags & CA_CI_MODULE_READY) { + tvhtrace(LS_EN50221, "slot ready on CAM #%d after ~%d msecs, path: %s", + lca->lca_number, i, lca->lca_ca_path); + break; + } + } + + /* Fix - Step 3: If the slot fails to initialise, give up */ + if(i >= (MAX_SLOT_READY_WAIT_SECS * 1000)) { + tvherror(LS_EN50221, "timeout after ~%d msecs to get slot info for CAM #%d, path: %s", + i, lca->lca_number, lca->lca_ca_path); + return NULL; + } + slot_id = en50221_tl_register_slot(lca->lca_tl, lca->lca_ca_fd, 0, 1000, 100); if (slot_id < 0) { tvherror(LS_EN50221, "slot registration failed"); @@ -766,6 +804,7 @@ csi.num, lca->lca_state_str); idnode_notify_title_changed(&lca->lca_id, NULL); lca->lca_state = state; + lca->lca_state_wait = 0; } if ((!lca->lca_en50221_thread_running) && @@ -774,6 +813,12 @@ lca->lca_en50221_thread_running = 1; tvhthread_create(&lca->lca_en50221_thread, NULL, linuxdvb_ca_en50221_thread, lca, "lnxdvb-ca"); + } else if (lca->lca_en50221_thread_running && + (state == CA_SLOT_STATE_MODULE_PRESENT) && + lca->lca_state_wait < (MAX_SLOT_READY_WAIT_SECS * 4)) + { + /* wait for the slot to move from PRESENT to READY */ + lca->lca_state_wait++; } else if (lca->lca_en50221_thread_running && (state != CA_SLOT_STATE_MODULE_READY)) { diff -urN tvheadend-4.2.2.old/src/input/mpegts/linuxdvb/linuxdvb_private.h tvheadend-4.2.2/src/input/mpegts/linuxdvb/linuxdvb_private.h --- tvheadend-4.2.2.old/src/input/mpegts/linuxdvb/linuxdvb_private.h 2017-05-16 11:15:24.000000000 +0000 +++ tvheadend-4.2.2/src/input/mpegts/linuxdvb/linuxdvb_private.h 2017-06-04 13:40:15.663449402 +0000 @@ -211,6 +211,7 @@ char *lca_ca_path; int lca_state; const char *lca_state_str; + int lca_state_wait; linuxdvb_ca_capmt_queue_t lca_capmt_queue; /* * CAM module info