X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fdvb_ci%2Fdvbci.cpp;h=bde394aa3111b13ef055e91e128419572eef616d;hp=1f1fa1663481265f1cf5b874e9f978e187197078;hb=69ad5b69a69b3a9006824832afb3fa8cecb061b9;hpb=54c4c8458e71ef9630420e0dead6897165255c5b diff --git a/lib/dvb_ci/dvbci.cpp b/lib/dvb_ci/dvbci.cpp index 1f1fa16..bde394a 100644 --- a/lib/dvb_ci/dvbci.cpp +++ b/lib/dvb_ci/dvbci.cpp @@ -7,6 +7,7 @@ #include #include // access to python config +#include #include #include #include @@ -17,6 +18,14 @@ #include +//#define CIDEBUG 1 + +#ifdef CIDEBUG + #define eDebugCI(x...) eDebug(x) +#else + #define eDebugCI(x...) +#endif + eDVBCIInterfaces *eDVBCIInterfaces::instance = 0; eDVBCIInterfaces::eDVBCIInterfaces() @@ -44,6 +53,22 @@ eDVBCIInterfaces::eDVBCIInterfaces() ++num_ci; } + for (eSmartPtrList::iterator it(m_slots.begin()); it != m_slots.end(); ++it) + it->setSource(TUNER_A); + + if (num_ci > 1) // // FIXME .. we force DM8000 when more than one CI Slot is avail + { + setInputSource(0, TUNER_A); + setInputSource(1, TUNER_B); + setInputSource(2, TUNER_C); + setInputSource(3, TUNER_D); + } + else + { + setInputSource(0, TUNER_A); + setInputSource(1, TUNER_B); + } + eDebug("done, found %d common interface slots", num_ci); } @@ -84,9 +109,6 @@ int eDVBCIInterfaces::reset(int slotid) if( (slot = getSlot(slotid)) == 0 ) return -1; - eDVBCISession::deleteSessions(slot); - ciRemoved(slot); - return slot->reset(); } @@ -113,7 +135,7 @@ int eDVBCIInterfaces::sendCAPMT(int slotid) while (it != m_pmt_handlers.end()) { eDVBCISlot *tmp = it->cislot; - while (tmp != slot) + while (tmp && tmp != slot) tmp = tmp->linked_next; if (tmp) { @@ -178,34 +200,38 @@ int eDVBCIInterfaces::cancelEnq(int slotid) void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot) { - for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); - it != m_pmt_handlers.end(); ++it) + if (slot->use_count) { - eServiceReferenceDVB ref; - it->pmthandler->getServiceReference(ref); - slot->removeService(ref.getServiceID().get()); - if (slot->use_count && !--slot->use_count) + eDebug("CI Slot %d: removed... usecount %d", slot->getSlotID(), slot->use_count); + for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); + it != m_pmt_handlers.end(); ++it) { - if (slot->linked_next) - slot->linked_next->setSource(slot->current_source); - else - setInputSource(slot->current_tuner, slot->current_source); - if (it->cislot == slot) // remove the base slot it->cislot = slot->linked_next; - else + else if (it->cislot) { - if (slot->linked_next) + eDVBCISlot *prevSlot = it->cislot, *hSlot = it->cislot->linked_next; + while (hSlot) { - eDVBCISlot *tmp = it->cislot; - while(tmp->linked_next != slot) - tmp = tmp->linked_next; - ASSERT(tmp); - tmp->linked_next = slot->linked_next; + if (hSlot == slot) { + prevSlot->linked_next = slot->linked_next; + break; + } + prevSlot = hSlot; + hSlot = hSlot->linked_next; } } - slot->linked_next=0; } + if (slot->linked_next) + slot->linked_next->setSource(slot->current_source); + else // last CI in chain + setInputSource(slot->current_tuner, slot->current_source); + slot->linked_next = 0; + slot->use_count=0; + slot->plugged=true; + slot->user_mapped=false; + slot->removeService(0xFFFF); + recheckPMTHandlers(); } } @@ -228,22 +254,50 @@ static bool canDescrambleMultipleServices(int slotid) void eDVBCIInterfaces::recheckPMTHandlers() { -// eDebug("recheckPMTHAndlers()"); + eDebugCI("recheckPMTHAndlers()"); for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); it != m_pmt_handlers.end(); ++it) { CAID_LIST caids; ePtr service; eServiceReferenceDVB ref; + eDVBCISlot *tmp = it->cislot; eDVBServicePMTHandler *pmthandler = it->pmthandler; eDVBServicePMTHandler::program p; + bool plugged_cis_exist = false; pmthandler->getServiceReference(ref); pmthandler->getService(service); + + eDebugCI("recheck %p %s", pmthandler, ref.toString().c_str()); + for (eSmartPtrList::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it) + if (ci_it->plugged && ci_it->getCAManager()) + { + eDebug("Slot %d plugged", ci_it->getSlotID()); + ci_it->plugged = false; + plugged_cis_exist = true; + } + + // check if this pmt handler has already assigned CI(s) .. and this CI(s) are already running + if (!plugged_cis_exist) + { + while(tmp) + { + if (!tmp->running_services.empty()) + break; + tmp=tmp->linked_next; + } + if (tmp) // we dont like to change tsmux for running services + { + eDebugCI("already assigned and running CI!\n"); + continue; + } + } + if (!pmthandler->getProgramInfo(p)) { int cnt=0; - for (std::set::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt) + for (caidSet::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt) caids.push_front(*x); if (service && cnt) service->m_ca = caids; @@ -252,13 +306,77 @@ void eDVBCIInterfaces::recheckPMTHandlers() if (service) caids = service->m_ca; - if (!caids.empty()) + if (caids.empty()) + continue; // unscrambled service + + for (eSmartPtrList::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it) { - for (eSmartPtrList::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it) + eDebugCI("check Slot %d", ci_it->getSlotID()); + bool useThis=false; + bool user_mapped=true; + eDVBCICAManagerSession *ca_manager = ci_it->getCAManager(); + + if (ca_manager) { - bool useThis=false; - eDVBCICAManagerSession *ca_manager = ci_it->getCAManager(); - if (ca_manager) + int mask=0; + if (!ci_it->possible_services.empty()) + { + mask |= 1; + serviceSet::iterator it = ci_it->possible_services.find(ref); + if (it != ci_it->possible_services.end()) + { + eDebug("'%s' is in service list of slot %d... so use it", ref.toString().c_str(), ci_it->getSlotID()); + useThis = true; + } + else // check parent + { + eServiceReferenceDVB parent_ref = ref.getParentServiceReference(); + if (parent_ref) + { + it = ci_it->possible_services.find(ref); + if (it != ci_it->possible_services.end()) + { + eDebug("parent '%s' of '%s' is in service list of slot %d... so use it", + parent_ref.toString().c_str(), ref.toString().c_str(), ci_it->getSlotID()); + useThis = true; + } + } + } + } + if (!useThis && !ci_it->possible_providers.empty()) + { + eDVBNamespace ns = ref.getDVBNamespace(); + mask |= 2; + if (!service) // subservice? + { + eServiceReferenceDVB parent_ref = ref.getParentServiceReference(); + eDVBDB::getInstance()->getService(parent_ref, service); + } + if (service) + { + providerSet::iterator it = ci_it->possible_providers.find(providerPair(service->m_provider_name, ns.get())); + if (it != ci_it->possible_providers.end()) + { + eDebug("'%s/%08x' is in provider list of slot %d... so use it", service->m_provider_name.c_str(), ns.get(), ci_it->getSlotID()); + useThis = true; + } + } + } + if (!useThis && !ci_it->possible_caids.empty()) + { + mask |= 4; + for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca) + { + caidSet::iterator it = ci_it->possible_caids.find(*ca); + if (it != ci_it->possible_caids.end()) + { + eDebug("caid '%04x' is in caid list of slot %d... so use it", *ca, ci_it->getSlotID()); + useThis = true; + break; + } + } + } + if (!useThis && !mask) { const std::vector &ci_caids = ca_manager->getCAIDs(); for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca) @@ -267,107 +385,143 @@ void eDVBCIInterfaces::recheckPMTHandlers() std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca); if ( z != ci_caids.end() && *z == *ca ) { -// eDebug("found ci for caid %04x", *z); - useThis=true; + eDebug("The CI in Slot %d has said it can handle caid %04x... so use it", ci_it->getSlotID(), *z); + useThis = true; + user_mapped = false; break; } } } + } - if (useThis) + if (useThis) + { + // check if this CI is already assigned to this pmthandler + eDVBCISlot *tmp = it->cislot; + while(tmp) { - if (ci_it->use_count) // check if this CI can descramble more than one service + if (tmp == ci_it) + break; + tmp=tmp->linked_next; + } + if (tmp) // ignore already assigned cislots... + { + eDebugCI("already assigned!"); + continue; + } + eDebugCI("current slot %d usecount %d", ci_it->getSlotID(), ci_it->use_count); + if (ci_it->use_count) // check if this CI can descramble more than one service + { + bool found = false; + useThis = false; + PMTHandlerList::iterator tmp = m_pmt_handlers.begin(); + while (!found && tmp != m_pmt_handlers.end()) { - useThis = false; - PMTHandlerList::iterator tmp = m_pmt_handlers.begin(); - while (tmp != m_pmt_handlers.end()) + eDebugCI("."); + eDVBCISlot *tmp_cislot = tmp->cislot; + while (!found && tmp_cislot) { - if ( tmp->cislot == ci_it && it != tmp ) + eDebugCI(".."); + eServiceReferenceDVB ref2; + tmp->pmthandler->getServiceReference(ref2); + if ( tmp_cislot == ci_it && it->pmthandler != tmp->pmthandler ) { - eServiceReferenceDVB ref2; - tmp->pmthandler->getServiceReference(ref2); + eDebugCI("check pmthandler %s for same service/tp", ref2.toString().c_str()); eDVBChannelID s1, s2; if (ref != ref2) { + eDebugCI("different services!"); ref.getChannelID(s1); ref2.getChannelID(s2); } - if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(ci_it->getSlotID()))) + if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(tmp_cislot->getSlotID()))) { - useThis = true; - break; + found = true; + eDebugCI("found!"); + eDVBCISlot *tmpci = it->cislot = tmp->cislot; + while(tmpci) + { + ++tmpci->use_count; + eDebug("(2)CISlot %d, usecount now %d", tmpci->getSlotID(), tmpci->use_count); + tmpci=tmpci->linked_next; + } } } - ++tmp; + tmp_cislot=tmp_cislot->linked_next; } + eDebugCI("..."); + ++tmp; } - if (useThis) - { - // check if this CI is already assigned to this pmthandler - eDVBCISlot *tmp = it->cislot; - while(tmp) - { - if (tmp == ci_it) - break; - } + } - if (tmp) // ignore already assigned cislots... - continue; + if (useThis) + { + if (ci_it->user_mapped) // we dont like to link user mapped CIs + { + eDebugCI("user mapped CI already in use... dont link!"); + continue; + } - ++ci_it->use_count; -// eDebug("usecount now %d", ci_it->use_count); + ++ci_it->use_count; + eDebug("(1)CISlot %d, usecount now %d", ci_it->getSlotID(), ci_it->use_count); - data_source ci_source=CI_A; - switch(ci_it->getSlotID()) - { - case 0: ci_source = CI_A; break; - case 1: ci_source = CI_B; break; - case 2: ci_source = CI_C; break; - case 3: ci_source = CI_D; break; - default: - eDebug("try to get source for CI %d!!\n", ci_it->getSlotID()); - break; - } + data_source ci_source=CI_A; + switch(ci_it->getSlotID()) + { + case 0: ci_source = CI_A; break; + case 1: ci_source = CI_B; break; + case 2: ci_source = CI_C; break; + case 3: ci_source = CI_D; break; + default: + eDebug("try to get source for CI %d!!\n", ci_it->getSlotID()); + break; + } - if (!it->cislot) + if (!it->cislot) + { + int tunernum = -1; + eUsePtr channel; + if (!pmthandler->getChannel(channel)) { - int tunernum = -1; - eUsePtr channel; - if (!pmthandler->getChannel(channel)) + ePtr frontend; + if (!channel->getFrontend(frontend)) { - ePtr frontend; - if (!channel->getFrontend(frontend)) - { - eDVBFrontend *fe = (eDVBFrontend*) &(*frontend); - tunernum = fe->getID(); - } + eDVBFrontend *fe = (eDVBFrontend*) &(*frontend); + tunernum = fe->getSlotID(); } - ASSERT(tunernum != -1); - data_source tuner_source = TUNER_A; - switch (tunernum) - { - case 0: tuner_source = TUNER_A; break; - case 1: tuner_source = TUNER_B; break; - case 2: tuner_source = TUNER_C; break; - case 3: tuner_source = TUNER_D; break; - default: - eDebug("try to get source for tuner %d!!\n", tunernum); - break; - } - ci_it->current_tuner = tunernum; - setInputSource(tunernum, ci_source); - ci_it->setSource(tuner_source); } - else + ASSERT(tunernum != -1); + data_source tuner_source = TUNER_A; + switch (tunernum) { - ci_it->current_tuner = it->cislot->current_tuner; - ci_it->linked_next = it->cislot; - ci_it->setSource(ci_it->linked_next->current_source); - ci_it->linked_next->setSource(ci_source); + case 0: tuner_source = TUNER_A; break; + case 1: tuner_source = TUNER_B; break; + case 2: tuner_source = TUNER_C; break; + case 3: tuner_source = TUNER_D; break; + default: + eDebug("try to get source for tuner %d!!\n", tunernum); + break; } - it->cislot = ci_it; - gotPMT(pmthandler); + ci_it->current_tuner = tunernum; + setInputSource(tunernum, ci_source); + ci_it->setSource(tuner_source); } + else + { + ci_it->current_tuner = it->cislot->current_tuner; + ci_it->linked_next = it->cislot; + ci_it->setSource(ci_it->linked_next->current_source); + ci_it->linked_next->setSource(ci_source); + } + it->cislot = ci_it; + eDebugCI("assigned!"); + gotPMT(pmthandler); + } + + if (it->cislot && user_mapped) // CI assigned to this pmthandler in this run.. and user mapped? then we break here.. we dont like to link other CIs to user mapped CIs + { + eDebugCI("user mapped CI assigned... dont link CIs!"); + break; } } } @@ -398,6 +552,7 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) if (it != m_pmt_handlers.end()) { eDVBCISlot *slot = it->cislot; + eDVBCISlot *base_slot = slot; eDVBServicePMTHandler *pmthandler = it->pmthandler; m_pmt_handlers.erase(it); @@ -421,20 +576,17 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) while(slot) { + eDVBCISlot *next = slot->linked_next; if (!sameServiceExist) { - if (slot->getNumOfServices() > 1) - { - eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt", - service_to_remove.toString().c_str()); - std::vector caids; - caids.push_back(0xFFFF); - slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service - } + eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt", + service_to_remove.toString().c_str()); + std::vector caids; + caids.push_back(0xFFFF); + slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service slot->removeService(service_to_remove.getServiceID().get()); } - eDVBCISlot *next = slot->linked_next; if (!--slot->use_count) { if (slot->linked_next) @@ -442,27 +594,28 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) else setInputSource(slot->current_tuner, slot->current_source); - if (it->cislot == slot) // remove the base slot - it->cislot = slot->linked_next; - else + if (base_slot != slot) { + eDVBCISlot *tmp = it->cislot; + while(tmp->linked_next != slot) + tmp = tmp->linked_next; + ASSERT(tmp); if (slot->linked_next) - { - eDVBCISlot *tmp = it->cislot; - while(tmp->linked_next != slot) - tmp = tmp->linked_next; - ASSERT(tmp); tmp->linked_next = slot->linked_next; - } + else + tmp->linked_next = 0; } - slot->linked_next=0; + else // removed old base slot.. update ptr + base_slot = slot->linked_next; + slot->linked_next = 0; + slot->user_mapped = false; } -// eDebug("use_count is now %d", slot->use_count); + eDebug("(3) slot %d usecount is now %d", slot->getSlotID(), slot->use_count); slot = next; } + // check if another service is waiting for the CI + recheckPMTHandlers(); } - // check if another service is waiting for the CI - recheckPMTHandlers(); } void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler) @@ -474,7 +627,9 @@ void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler) eDVBCISlot *tmp = it->cislot; while(tmp) { - tmp->sendCAPMT(pmthandler); + eDebugCI("check slot %d %d %d", tmp->getSlotID(), tmp->running_services.empty(), canDescrambleMultipleServices(tmp->getSlotID())); + if (tmp->running_services.empty() || canDescrambleMultipleServices(tmp->getSlotID())) + tmp->sendCAPMT(pmthandler); tmp = tmp->linked_next; } } @@ -486,7 +641,7 @@ int eDVBCIInterfaces::getMMIState(int slotid) if( (slot = getSlot(slotid)) == 0 ) return -1; - + return slot->getMMIState(); } @@ -494,86 +649,296 @@ int eDVBCIInterfaces::setInputSource(int tuner_no, data_source source) { // eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); // eDebug("eDVBCIInterfaces::setInputSource(%d %d)", tuner_no, (int)source); -#if defined(DM8000) - char buf[64]; - snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no); + if (getNumOfSlots() > 1) // FIXME .. we force DM8000 when more than one CI Slot is avail + { + char buf[64]; + snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no); - FILE *input=0; - if((input = fopen(buf, "wb")) == NULL) { - eDebug("cannot open %s", buf); - return 0; - } + FILE *input=0; + if((input = fopen(buf, "wb")) == NULL) { + eDebug("cannot open %s", buf); + return 0; + } - if (input > 3) - eDebug("setInputSource(%d, %d) failed... dm8000 just have four inputs", tuner_no, (int)source); + if (tuner_no > 3) + eDebug("setInputSource(%d, %d) failed... dm8000 just have four inputs", tuner_no, (int)source); - switch(source) - { - case CI_A: - fprintf(input, "CI0"); - break; - case CI_B: - fprintf(input, "CI1"); - break; - case CI_C: - fprintf(input, "CI2"); - break; - case CI_D: - fprintf(input, "CI3"); - break; - case TUNER_A: - fprintf(input, "A"); - break; - case TUNER_B: - fprintf(input, "B"); - break; - case TUNER_C: - fprintf(input, "C"); - break; - case TUNER_D: - fprintf(input, "D"); - break; - default: - eDebug("setInputSource for input %d failed!!!\n", (int)source); + switch(source) + { + case CI_A: + fprintf(input, "CI0"); + break; + case CI_B: + fprintf(input, "CI1"); + break; + case CI_C: + fprintf(input, "CI2"); break; + case CI_D: + fprintf(input, "CI3"); + break; + case TUNER_A: + fprintf(input, "A"); + break; + case TUNER_B: + fprintf(input, "B"); + break; + case TUNER_C: + fprintf(input, "C"); + break; + case TUNER_D: + fprintf(input, "D"); + break; + default: + eDebug("setInputSource for input %d failed!!!\n", (int)source); + break; + } + + fclose(input); } + else // DM7025 + { + char buf[64]; + snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no); - fclose(input); -#else // force DM7025 - char buf[64]; - snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no); + if (tuner_no > 1) + eDebug("setInputSource(%d, %d) failed... dm7025 just have two inputs", tuner_no, (int)source); + + FILE *input=0; + if((input = fopen(buf, "wb")) == NULL) { + eDebug("cannot open %s", buf); + return 0; + } + + switch(source) + { + case CI_A: + fprintf(input, "CI"); + break; + case TUNER_A: + fprintf(input, "A"); + break; + case TUNER_B: + fprintf(input, "B"); + break; + default: + eDebug("setInputSource for input %d failed!!!\n", (int)source); + break; + } - if (tuner_no > 1) - eDebug("setInputSource(%d, %d) failed... dm7025 just have two inputs", tuner_no, (int)source); + fclose(input); + } + eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source); + return 0; +} - FILE *input=0; - if((input = fopen(buf, "wb")) == NULL) { - eDebug("cannot open %s", buf); +PyObject *eDVBCIInterfaces::getDescrambleRules(int slotid) +{ + eDVBCISlot *slot = getSlot(slotid); + if (!slot) + { + char tmp[255]; + snprintf(tmp, 255, "eDVBCIInterfaces::getDescrambleRules try to get rules for CI Slot %d... but just %d slots are available", slotid, m_slots.size()); + PyErr_SetString(PyExc_StandardError, tmp); return 0; } + ePyObject tuple = PyTuple_New(3); + int caids = slot->possible_caids.size(); + int services = slot->possible_services.size(); + int providers = slot->possible_providers.size(); + ePyObject caid_list = PyList_New(caids); + ePyObject service_list = PyList_New(services); + ePyObject provider_list = PyList_New(providers); + caidSet::iterator caid_it(slot->possible_caids.begin()); + while(caids) + { + --caids; + PyList_SET_ITEM(caid_list, caids, PyLong_FromLong(*caid_it)); + ++caid_it; + } + serviceSet::iterator ref_it(slot->possible_services.begin()); + while(services) + { + --services; + PyList_SET_ITEM(service_list, services, PyString_FromString(ref_it->toString().c_str())); + ++ref_it; + } + providerSet::iterator provider_it(slot->possible_providers.begin()); + while(providers) + { + ePyObject tuple = PyTuple_New(2); + PyTuple_SET_ITEM(tuple, 0, PyString_FromString(provider_it->first.c_str())); + PyTuple_SET_ITEM(tuple, 1, PyLong_FromUnsignedLong(provider_it->second)); + --providers; + PyList_SET_ITEM(provider_list, providers, tuple); + ++provider_it; + } + PyTuple_SET_ITEM(tuple, 0, service_list); + PyTuple_SET_ITEM(tuple, 1, provider_list); + PyTuple_SET_ITEM(tuple, 2, caid_list); + return tuple; +} + +const char *PyObject_TypeStr(PyObject *o) +{ + return o->ob_type && o->ob_type->tp_name ? o->ob_type->tp_name : "unknown object type"; +} - switch(source) +RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) obj ) +{ + eDVBCISlot *slot = getSlot(slotid); + if (!slot) { - case CI_A: - fprintf(input, "CI"); - break; - case TUNER_A: - fprintf(input, "A"); - break; - case TUNER_B: - fprintf(input, "B"); - break; - default: - eDebug("setInputSource for input %d failed!!!\n", (int)source); - break; + char tmp[255]; + snprintf(tmp, 255, "eDVBCIInterfaces::setDescrambleRules try to set rules for CI Slot %d... but just %d slots are available", slotid, m_slots.size()); + PyErr_SetString(PyExc_StandardError, tmp); + return -1; } + if (!PyTuple_Check(obj)) + { + char tmp[255]; + snprintf(tmp, 255, "2nd argument of setDescrambleRules is not a tuple.. it is a '%s'!!", PyObject_TypeStr(obj)); + PyErr_SetString(PyExc_StandardError, tmp); + return -1; + } + if (PyTuple_Size(obj) != 3) + { + const char *errstr = "eDVBCIInterfaces::setDescrambleRules not enough entrys in argument tuple!!\n" + "first argument should be a pythonlist with possible services\n" + "second argument should be a pythonlist with possible providers/dvbnamespace tuples\n" + "third argument should be a pythonlist with possible caids"; + PyErr_SetString(PyExc_StandardError, errstr); + return -1; + } + ePyObject service_list = PyTuple_GET_ITEM(obj, 0); + ePyObject provider_list = PyTuple_GET_ITEM(obj, 1); + ePyObject caid_list = PyTuple_GET_ITEM(obj, 2); + if (!PyList_Check(service_list) || !PyList_Check(provider_list) || !PyList_Check(caid_list)) + { + char errstr[512]; + snprintf(errstr, 512, "eDVBCIInterfaces::setDescrambleRules incorrect data types in argument tuple!!\n" + "first argument(%s) should be a pythonlist with possible services (reference strings)\n" + "second argument(%s) should be a pythonlist with possible providers (providername strings)\n" + "third argument(%s) should be a pythonlist with possible caids (ints)", + PyObject_TypeStr(service_list), PyObject_TypeStr(provider_list), PyObject_TypeStr(caid_list)); + PyErr_SetString(PyExc_StandardError, errstr); + return -1; + } + slot->possible_caids.clear(); + slot->possible_services.clear(); + slot->possible_providers.clear(); + int size = PyList_Size(service_list); + while(size) + { + --size; + ePyObject refstr = PyList_GET_ITEM(service_list, size); + if (!PyString_Check(refstr)) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in service list is not a string.. it is '%s'!!", PyObject_TypeStr(refstr)); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + char *tmpstr = PyString_AS_STRING(refstr); + eServiceReference ref(tmpstr); + if (ref.valid()) + slot->possible_services.insert(ref); + else + eDebug("eDVBCIInterfaces::setDescrambleRules '%s' is not a valid service reference... ignore!!", tmpstr); + }; + size = PyList_Size(provider_list); + while(size) + { + --size; + ePyObject tuple = PyList_GET_ITEM(provider_list, size); + if (!PyTuple_Check(tuple)) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in provider list is not a tuple it is '%s'!!", PyObject_TypeStr(tuple)); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + if (PyTuple_Size(tuple) != 2) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules provider tuple has %d instead of 2 entries!!", PyTuple_Size(tuple)); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + if (!PyString_Check(PyTuple_GET_ITEM(tuple, 0))) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules 1st entry in provider tuple is not a string it is '%s'", PyObject_TypeStr(PyTuple_GET_ITEM(tuple, 0))); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + if (!PyLong_Check(PyTuple_GET_ITEM(tuple, 1))) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules 2nd entry in provider tuple is not a long it is '%s'", PyObject_TypeStr(PyTuple_GET_ITEM(tuple, 1))); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + char *tmpstr = PyString_AS_STRING(PyTuple_GET_ITEM(tuple, 0)); + uint32_t orbpos = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(tuple, 1)); + if (strlen(tmpstr)) + slot->possible_providers.insert(std::pair(tmpstr, orbpos)); + else + eDebug("eDVBCIInterfaces::setDescrambleRules ignore invalid entry in provider tuple (string is empty)!!"); + }; + size = PyList_Size(caid_list); + while(size) + { + --size; + ePyObject caid = PyList_GET_ITEM(caid_list, size); + if (!PyLong_Check(caid)) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in caid list is not a long it is '%s'!!", PyObject_TypeStr(caid)); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + int tmpcaid = PyLong_AsLong(caid); + if (tmpcaid > 0 && tmpcaid < 0x10000) + slot->possible_caids.insert(tmpcaid); + else + eDebug("eDVBCIInterfaces::setDescrambleRules %d is not a valid caid... ignore!!", tmpcaid); + }; + return 0; +} - fclose(input); -#endif - eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source); +PyObject *eDVBCIInterfaces::readCICaIds(int slotid) +{ + eDVBCISlot *slot = getSlot(slotid); + if (!slot) + { + char tmp[255]; + snprintf(tmp, 255, "eDVBCIInterfaces::readCICaIds try to get CAIds for CI Slot %d... but just %d slots are available", slotid, m_slots.size()); + PyErr_SetString(PyExc_StandardError, tmp); + } + else + { + int idx=0; + eDVBCICAManagerSession *ca_manager = slot->getCAManager(); + const std::vector *ci_caids = ca_manager ? &ca_manager->getCAIDs() : 0; + ePyObject list = PyList_New(ci_caids ? ci_caids->size() : 0); + if (ci_caids) + { + for (std::vector::const_iterator it = ci_caids->begin(); it != ci_caids->end(); ++it) + PyList_SET_ITEM(list, idx++, PyLong_FromLong(*it)); + } + return list; + } return 0; } +int eDVBCIInterfaces::setCIClockRate(int slotid, int rate) +{ + eDVBCISlot *slot = getSlot(slotid); + if (slot) + return slot->setClockRate(rate); + return -1; +} int eDVBCISlot::send(const unsigned char *data, size_t len) { @@ -600,17 +965,17 @@ int eDVBCISlot::send(const unsigned char *data, size_t len) void eDVBCISlot::data(int what) { + eDebugCI("CISlot %d what %d\n", getSlotID(), what); if(what == eSocketNotifier::Priority) { if(state != stateRemoved) { state = stateRemoved; - eDebug("ci removed"); while(sendqueue.size()) { delete [] sendqueue.top().data; sendqueue.pop(); } - eDVBCIInterfaces::getInstance()->ciRemoved(this); eDVBCISession::deleteSessions(this); + eDVBCIInterfaces::getInstance()->ciRemoved(this); notifier->setRequested(eSocketNotifier::Read); eDVBCI_UI::getInstance()->setState(getSlotID(),0); } @@ -621,7 +986,7 @@ void eDVBCISlot::data(int what) reset(); if(state != stateInserted) { - eDebug("ci inserted"); + eDebug("ci inserted in slot %d", getSlotID()); state = stateInserted; eDVBCI_UI::getInstance()->setState(getSlotID(),1); notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority); @@ -669,19 +1034,25 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) ca_manager = 0; use_count = 0; linked_next = 0; + user_mapped = false; + plugged = true; slotid = nr; sprintf(filename, "/dev/ci%d", nr); +// possible_caids.insert(0x1702); +// possible_providers.insert(providerPair("PREMIERE", 0xC00000)); +// possible_services.insert(eServiceReference("1:0:1:2A:4:85:C00000:0:0:0:")); + fd = ::open(filename, O_RDWR | O_NONBLOCK); - eDebug("eDVBCISlot has fd %d", fd); + eDebugCI("CI Slot %d has fd %d", getSlotID(), fd); state = stateInvalid; if (fd >= 0) { - notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); + notifier = eSocketNotifier::create(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); CONNECT(notifier->activated, eDVBCISlot::data); } else { @@ -691,6 +1062,7 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) eDVBCISlot::~eDVBCISlot() { + eDVBCISession::deleteSessions(this); } void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session ) @@ -715,7 +1087,7 @@ int eDVBCISlot::getSlotID() int eDVBCISlot::reset() { - eDebug("edvbcislot: reset requested"); + eDebug("CI Slot %d: reset requested", getSlotID()); if (state == stateInvalid) { @@ -738,7 +1110,7 @@ int eDVBCISlot::reset() int eDVBCISlot::startMMI() { - eDebug("edvbcislot: startMMI()"); + eDebug("CI Slot %d: startMMI()", getSlotID()); if(application_manager) application_manager->startMMI(); @@ -748,7 +1120,7 @@ int eDVBCISlot::startMMI() int eDVBCISlot::stopMMI() { - eDebug("edvbcislot: stopMMI()"); + eDebug("CI Slot %d: stopMMI()", getSlotID()); if(mmi_session) mmi_session->stopMMI(); @@ -758,7 +1130,7 @@ int eDVBCISlot::stopMMI() int eDVBCISlot::answerText(int answer) { - eDebug("edvbcislot: answerText(%d)", answer); + eDebug("CI Slot %d: answerText(%d)", getSlotID(), answer); if(mmi_session) mmi_session->answerText(answer); @@ -776,7 +1148,7 @@ int eDVBCISlot::getMMIState() int eDVBCISlot::answerEnq(char *value) { - eDebug("edvbcislot: answerENQ(%s)", value); + eDebug("CI Slot %d: answerENQ(%s)", getSlotID(), value); if(mmi_session) mmi_session->answerEnq(value); @@ -786,7 +1158,7 @@ int eDVBCISlot::answerEnq(char *value) int eDVBCISlot::cancelEnq() { - eDebug("edvbcislot: cancelENQ"); + eDebug("CI Slot %d: cancelENQ", getSlotID()); if(mmi_session) mmi_session->cancelEnq(); @@ -832,9 +1204,9 @@ int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vectorgetNumOfSlots() > 1) // FIXME .. we force DM8000 when more than one CI Slot is avail + { + char buf[64]; + snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slotid); + FILE *ci = fopen(buf, "wb"); + switch(source) + { + case CI_A: + fprintf(ci, "CI0"); + break; + case CI_B: + fprintf(ci, "CI1"); + break; + case CI_C: + fprintf(ci, "CI2"); + break; + case CI_D: + fprintf(ci, "CI3"); + break; + case TUNER_A: + fprintf(ci, "A"); + break; + case TUNER_B: + fprintf(ci, "B"); + break; + case TUNER_C: + fprintf(ci, "C"); + break; + case TUNER_D: + fprintf(ci, "D"); + break; + default: + eDebug("CI Slot %d: setSource %d failed!!!\n", getSlotID(), (int)source); + break; + } + fclose(ci); + } + else // DM7025 + { +// eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); +// eDebug("eDVBCISlot::enableTS(%d %d)", enable, (int)source); + FILE *ci = fopen("/proc/stb/tsmux/input2", "wb"); + if(ci == NULL) { + eDebug("cannot open /proc/stb/tsmux/input2"); + return 0; + } + if (source != TUNER_A && source != TUNER_B) + eDebug("CI Slot %d: setSource %d failed!!!\n", getSlotID(), (int)source); + else + fprintf(ci, "%s", source==TUNER_A ? "A" : "B"); // configure CI data source (TunerA, TunerB) + fclose(ci); + } + eDebug("CI Slot %d setSource(%d)", getSlotID(), (int)source); + return 0; +} + +int eDVBCISlot::setClockRate(int rate) +{ char buf[64]; - snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slotid); + snprintf(buf, 64, "/proc/stb/tsmux/ci%d_tsclk", slotid); FILE *ci = fopen(buf, "wb"); - switch(source) + if (ci) { - case CI_A: - fprintf(ci, "CI0"); - break; - case CI_B: - fprintf(ci, "CI1"); - break; - case CI_C: - fprintf(ci, "CI2"); - break; - case CI_D: - fprintf(ci, "CI3"); - break; - case TUNER_A: - fprintf(ci, "A"); - break; - case TUNER_B: - fprintf(ci, "B"); - break; - case TUNER_C: - fprintf(ci, "C"); - break; - case TUNER_D: - fprintf(ci, "D"); - break; - default: - eDebug("setSource %d failed!!!\n", (int)source); - break; - } - fclose(ci); -#else // force DM7025 -// eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); -// eDebug("eDVBCISlot::enableTS(%d %d)", enable, (int)source); - FILE *ci = fopen("/proc/stb/tsmux/input2", "wb"); - if(ci == NULL) { - eDebug("cannot open /proc/stb/tsmux/input2"); + if (rate) + fprintf(ci, "high"); + else + fprintf(ci, "normal"); + fclose(ci); return 0; } - if (source != TUNER_A && source != TUNER_B) - eDebug("setSource %d failed!!!\n", (int)source); - else - fprintf(ci, "%s", source==TUNER_A ? "A" : "B"); // configure CI data source (TunerA, TunerB) - fclose(ci); -#endif - eDebug("eDVBCISlot->setSource(%d)", (int)source); - return 0; + return -1; } eAutoInitP0 init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");