X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/f58346453b1ab66a35c5b12416aa609eb64ab0de..b5682256605acc192f4dddea11b0595344348bcb:/lib/dvb_ci/dvbci.cpp diff --git a/lib/dvb_ci/dvbci.cpp b/lib/dvb_ci/dvbci.cpp index 80573e89..85c18794 100644 --- a/lib/dvb_ci/dvbci.cpp +++ b/lib/dvb_ci/dvbci.cpp @@ -6,6 +6,8 @@ #include #include +#include // access to python config +#include #include #include #include @@ -43,6 +45,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); } @@ -61,29 +79,32 @@ eDVBCISlot *eDVBCIInterfaces::getSlot(int slotid) if(i->getSlotID() == slotid) return i; - printf("FIXME: request for unknown slot\n"); + eDebug("FIXME: request for unknown slot"); return 0; } -int eDVBCIInterfaces::reset(int slotid) +int eDVBCIInterfaces::getSlotState(int slotid) { eDVBCISlot *slot; if( (slot = getSlot(slotid)) == 0 ) - return -1; + return eDVBCISlot::stateInvalid; - return slot->reset(); + return slot->getState(); } -int eDVBCIInterfaces::enableTS(int slotid, int enable) +int eDVBCIInterfaces::reset(int slotid) { eDVBCISlot *slot; if( (slot = getSlot(slotid)) == 0 ) return -1; - return slot->enableTS(enable); + eDVBCISession::deleteSessions(slot); + ciRemoved(slot); + + return slot->reset(); } int eDVBCIInterfaces::initialize(int slotid) @@ -93,19 +114,9 @@ int eDVBCIInterfaces::initialize(int slotid) if( (slot = getSlot(slotid)) == 0 ) return -1; - slot->resetPrevSentCAPMTVersion(); - PMTHandlerList::iterator it = m_pmt_handlers.begin(); - while (it != m_pmt_handlers.end()) - { - if ( it->cislot == slot ) - { - slot->sendCAPMT(it->pmthandler); // send capmt - break; - } - ++it; - } + slot->removeService(); - return slot->initialize(); + return sendCAPMT(slotid); } int eDVBCIInterfaces::sendCAPMT(int slotid) @@ -115,19 +126,21 @@ int eDVBCIInterfaces::sendCAPMT(int slotid) if( (slot = getSlot(slotid)) == 0 ) return -1; - slot->resetPrevSentCAPMTVersion(); PMTHandlerList::iterator it = m_pmt_handlers.begin(); while (it != m_pmt_handlers.end()) { - if ( it->cislot == slot ) + eDVBCISlot *tmp = it->cislot; + while (tmp && tmp != slot) + tmp = tmp->linked_next; + if (tmp) { - slot->sendCAPMT(it->pmthandler); // send capmt - return 0; + tmp->sendCAPMT(it->pmthandler); // send capmt + break; } ++it; } - return -1; + return 0; } int eDVBCIInterfaces::startMMI(int slotid) @@ -180,44 +193,268 @@ int eDVBCIInterfaces::cancelEnq(int slotid) return slot->cancelEnq(); } -void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler) +void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot) { - CIPmtHandler new_handler(pmthandler); - - eServiceReferenceDVB service; - pmthandler->getService(service); + for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); + it != m_pmt_handlers.end(); ++it) + { + eServiceReferenceDVB ref; + it->pmthandler->getServiceReference(ref); + slot->removeService(ref.getServiceID().get()); + if (slot->use_count && !--slot->use_count) + { + if (slot->linked_next) + slot->linked_next->setSource(slot->current_source); + else // last CI in chain + setInputSource(slot->current_tuner, slot->current_source); - eDebug("[eDVBCIInterfaces] addPMTHandler %s", service.toString().c_str()); + if (it->cislot == slot) // remove the base slot + it->cislot = slot->linked_next; + else + { + eDVBCISlot *tmp = it->cislot; + while(tmp->linked_next != slot) + tmp = tmp->linked_next; + ASSERT(tmp); + if (slot->linked_next) + tmp->linked_next = slot->linked_next; + else + tmp->linked_next = 0; + } + slot->linked_next=0; + } + } +} - // HACK the first service get the CI.. - eSmartPtrList::iterator ci_it(m_slots.begin()); - for (; ci_it != m_slots.end(); ++ci_it) +static bool canDescrambleMultipleServices(int slotid) +{ + char configStr[255]; + snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid); + std::string str; + ePythonConfigQuery::getConfigValue(configStr, str); + if ( str == "auto" ) { - if (ci_it->use_count) - continue; - ci_it->use_count=1; - new_handler.cislot = ci_it; - new_handler.cislot->resetPrevSentCAPMTVersion(); + std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid); + if (appname.find("AlphaCrypt") != std::string::npos) + return true; } + else if (str == "yes") + return true; + return false; +} - if (ci_it == m_slots.end()) +void eDVBCIInterfaces::recheckPMTHandlers() +{ +// eDebug("recheckPMTHAndlers()"); + for (PMTHandlerList::iterator it(m_pmt_handlers.begin()); + it != m_pmt_handlers.end(); ++it) { - PMTHandlerList::iterator it = m_pmt_handlers.begin(); - while (it != m_pmt_handlers.end()) + CAID_LIST caids; + ePtr service; + eServiceReferenceDVB ref; + eDVBServicePMTHandler *pmthandler = it->pmthandler; + eDVBServicePMTHandler::program p; + + pmthandler->getServiceReference(ref); + pmthandler->getService(service); + if (!pmthandler->getProgramInfo(p)) { - eServiceReferenceDVB ref; - it->pmthandler->getService(ref); - if ( service == ref && it->cislot ) + int cnt=0; + for (std::set::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt) + caids.push_front(*x); + if (service && cnt) + service->m_ca = caids; + } + + if (service) + caids = service->m_ca; + + if (caids.empty()) + continue; // unscrambled service + + for (eSmartPtrList::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it) + { + bool useThis=false; + eDVBCICAManagerSession *ca_manager = ci_it->getCAManager(); + if (ca_manager) { - new_handler.cislot = it->cislot; - ++new_handler.cislot->use_count; - break; + int mask=0; + if (!ci_it->possible_services.empty()) + { + mask |= 1; + std::set::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; + } + } + if (!useThis && !ci_it->possible_providers.empty()) + { + bool parent=false; + mask |= 2; + if (!service) // subservice? + { + eServiceReferenceDVB parent_ref = ref.getParentServiceReference(); + eDVBDB::getInstance()->getService(parent_ref, service); + parent=true; + } + if (service) + { + std::set::iterator it = ci_it->possible_providers.find(service->m_provider_name); + if (it != ci_it->possible_providers.end()) + { + eDebug("'%s' is in provider list of slot %d... so use it", service->m_provider_name.c_str(), ci_it->getSlotID()); + useThis = true; + } + } + } + if (!useThis && !ci_it->possible_caids.empty()) + { + for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca) + { + std::set::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) + { + std::vector::const_iterator z = + std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca); + if ( z != ci_caids.end() && *z == *ca ) + { + eDebug("The CI in Slot %d has said it can handle caid %04x... so use it", ci_it->getSlotID(), *z); + useThis=true; + break; + } + } + } + } + + if (useThis) + { + if (ci_it->use_count) // check if this CI can descramble more than one service + { + useThis = false; + PMTHandlerList::iterator tmp = m_pmt_handlers.begin(); + while (tmp != m_pmt_handlers.end()) + { + if ( tmp->cislot == ci_it && it != tmp ) + { + eServiceReferenceDVB ref2; + tmp->pmthandler->getServiceReference(ref2); + eDVBChannelID s1, s2; + if (ref != ref2) + { + ref.getChannelID(s1); + ref2.getChannelID(s2); + } + if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(ci_it->getSlotID()))) + { + useThis = true; + break; + } + } + ++tmp; + } + } + if (useThis) + { + // check if this CI is already assigned to this pmthandler + eDVBCISlot *tmp = it->cislot; + while(tmp) + { + if (tmp == ci_it) + break; + tmp=tmp->linked_next; + } + + if (tmp) // ignore already assigned cislots... + continue; + + ++ci_it->use_count; +// eDebug("usecount now %d", 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; + } + + if (!it->cislot) + { + int tunernum = -1; + eUsePtr channel; + if (!pmthandler->getChannel(channel)) + { + ePtr frontend; + if (!channel->getFrontend(frontend)) + { + 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 + { + 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; + gotPMT(pmthandler); + } } - ++it; } } +} + +void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler) +{ + // check if this pmthandler is already registered + PMTHandlerList::iterator it = m_pmt_handlers.begin(); + while (it != m_pmt_handlers.end()) + { + if ( *it++ == pmthandler ) + return; + } - m_pmt_handlers.push_back(new_handler); + eServiceReferenceDVB ref; + pmthandler->getServiceReference(ref); + eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str()); + + m_pmt_handlers.push_back(CIPmtHandler(pmthandler)); + recheckPMTHandlers(); } void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) @@ -226,42 +463,86 @@ void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler) if (it != m_pmt_handlers.end()) { eDVBCISlot *slot = it->cislot; -// eDVBServicePMTHandler *pmthandler = it->pmthandler; + eDVBServicePMTHandler *pmthandler = it->pmthandler; m_pmt_handlers.erase(it); - if (slot && !--slot->use_count) + + eServiceReferenceDVB service_to_remove; + pmthandler->getServiceReference(service_to_remove); + + bool sameServiceExist=false; + for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i) { -#if 0 - eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt"); - std::vector caids; - caids.push_back(0xFFFF); - slot->resetPrevSentCAPMTVersion(); - slot->sendCAPMT(pmthandler, caids); -#endif - // check if another service is running - it = m_pmt_handlers.begin(); - while (it != m_pmt_handlers.end()) + if (i->cislot) { - if ( !it->cislot ) + eServiceReferenceDVB ref; + i->pmthandler->getServiceReference(ref); + if ( ref == service_to_remove ) { - it->cislot = slot; - ++slot->use_count; - slot->resetPrevSentCAPMTVersion(); - slot->sendCAPMT(it->pmthandler); + sameServiceExist=true; break; } - ++it; } } + + while(slot) + { + 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 + } + slot->removeService(service_to_remove.getServiceID().get()); + } + + eDVBCISlot *next = slot->linked_next; + if (!--slot->use_count) + { + 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 + { + eDVBCISlot *tmp = it->cislot; + while(tmp->linked_next != slot) + tmp = tmp->linked_next; + ASSERT(tmp); + if (slot->linked_next) + tmp->linked_next = slot->linked_next; + else + tmp->linked_next = 0; + } + slot->linked_next=0; + } +// eDebug("use_count is now %d", slot->use_count); + slot = next; + } } + // check if another service is waiting for the CI + recheckPMTHandlers(); } void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler) { eDebug("[eDVBCIInterfaces] gotPMT"); PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler); - eServiceReferenceDVB service; - if ( it != m_pmt_handlers.end() && it->cislot) - it->cislot->sendCAPMT(pmthandler); + if (it != m_pmt_handlers.end() && it->cislot) + { + eDVBCISlot *tmp = it->cislot; + while(tmp) + { + tmp->sendCAPMT(pmthandler); + tmp = tmp->linked_next; + } + } } int eDVBCIInterfaces::getMMIState(int slotid) @@ -274,20 +555,262 @@ int eDVBCIInterfaces::getMMIState(int slotid) return slot->getMMIState(); } +int eDVBCIInterfaces::setInputSource(int tuner_no, data_source source) +{ +// eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); +// eDebug("eDVBCIInterfaces::setInputSource(%d %d)", tuner_no, (int)source); + 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; + } + + 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); + break; + } + + fclose(input); + } + else // 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; + } + + fclose(input); + } + eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source); + return 0; +} + +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); + std::set::iterator caid_it(slot->possible_caids.begin()); + while(caids) + { + --caids; + PyTuple_SET_ITEM(caid_list, caids, PyLong_FromLong(*caid_it)); + ++caid_it; + } + std::set::iterator ref_it(slot->possible_services.begin()); + while(services) + { + --services; + PyTuple_SET_ITEM(service_list, services, PyString_FromString(ref_it->toString().c_str())); + ++ref_it; + } + std::set::iterator provider_it(slot->possible_providers.begin()); + while(providers) + { + --providers; + PyTuple_SET_ITEM(provider_list, providers, PyString_FromString(provider_it->c_str())); + ++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"; +} + +RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) obj ) +{ + eDVBCISlot *slot = getSlot(slotid); + if (!slot) + { + 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\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 str = PyList_GET_ITEM(provider_list, size); + if (!PyString_Check(str)) + { + char buf[255]; + snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in provider list is not a string it is '%s'!!", PyObject_TypeStr(str)); + PyErr_SetString(PyExc_StandardError, buf); + return -1; + } + char *tmpstr = PyString_AS_STRING(str); + if (strlen(tmpstr)) + slot->possible_providers.insert(tmpstr); + else + eDebug("eDVBCIInterfaces::setDescrambleRules ignore invalid entry in provider name list!!"); + }; + size = PyList_Size(caid_list); + while(size) + { + --size; + ePyObject caid = PyList_GET_ITEM(caid_list, size); + if (!PyInt_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 = PyInt_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; +} + int eDVBCISlot::send(const unsigned char *data, size_t len) { - int res; + int res=0; //int i; - //printf("< "); + //eDebugNoNewLine("< "); //for(i=0;isetRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); + if (res < 0 || (unsigned int)res != len) + { + unsigned char *d = new unsigned char[len]; + memcpy(d, data, len); + sendqueue.push( queueData(d, len) ); + notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); + } return res; } @@ -297,45 +820,58 @@ void eDVBCISlot::data(int what) if(what == eSocketNotifier::Priority) { if(state != stateRemoved) { state = stateRemoved; - enableTS(0); - printf("ci removed\n"); + eDebug("ci removed"); + while(sendqueue.size()) + { + delete [] sendqueue.top().data; + sendqueue.pop(); + } + eDVBCIInterfaces::getInstance()->ciRemoved(this); + eDVBCISession::deleteSessions(this); notifier->setRequested(eSocketNotifier::Read); - //HACK - eDVBCI_UI::getInstance()->setState(0,0); + eDVBCI_UI::getInstance()->setState(getSlotID(),0); } return; } - __u8 data[4096]; - int r; - r = ::read(fd, data, 4096); + if (state == stateInvalid) + reset(); if(state != stateInserted) { - state = stateInserted; eDebug("ci inserted"); - - //HACK - eDVBCI_UI::getInstance()->setState(0,1); - + state = stateInserted; + eDVBCI_UI::getInstance()->setState(getSlotID(),1); + notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority); /* enable PRI to detect removal or errors */ - notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Write); } - if(r > 0) { - //int i; - //printf("> "); - //for(i=0;isetRequested(eSocketNotifier::Read|eSocketNotifier::Priority|eSocketNotifier::Write); - return; + if (what & eSocketNotifier::Read) { + __u8 data[4096]; + int r; + r = ::read(fd, data, 4096); + if(r > 0) { +// int i; +// eDebugNoNewLine("> "); +// for(i=0;isetRequested(eSocketNotifier::Read | eSocketNotifier::Priority); + else if (what & eSocketNotifier::Write) { + if (!sendqueue.empty()) { + const queueData &qe = sendqueue.top(); + int res = ::write(fd, qe.data, qe.len); + if (res >= 0 && (unsigned int)res == qe.len) + { + delete [] qe.data; + sendqueue.pop(); + } } + else + notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority); } } @@ -349,6 +885,7 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) mmi_session = 0; ca_manager = 0; use_count = 0; + linked_next = 0; slotid = nr; @@ -357,12 +894,11 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) fd = ::open(filename, O_RDWR | O_NONBLOCK); eDebug("eDVBCISlot has fd %d", fd); - - state = stateInserted; + state = stateInvalid; if (fd >= 0) { - notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority); + notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); CONNECT(notifier->activated, eDVBCISlot::data); } else { @@ -372,7 +908,7 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) eDVBCISlot::~eDVBCISlot() { - enableTS(0); + delete notifier; } void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session ) @@ -397,24 +933,30 @@ int eDVBCISlot::getSlotID() int eDVBCISlot::reset() { - printf("edvbcislot: reset requested\n"); + eDebug("edvbcislot: reset requested"); - enableTS(0); + if (state == stateInvalid) + { + unsigned char buf[256]; + eDebug("ci flush"); + while(::read(fd, buf, 256)>0); + state = stateResetted; + } - ioctl(fd, 0); + while(sendqueue.size()) + { + delete [] sendqueue.top().data; + sendqueue.pop(); + } - return 0; -} + ioctl(fd, 0); -int eDVBCISlot::initialize() -{ - printf("edvbcislot: initialize()\n"); return 0; } int eDVBCISlot::startMMI() { - printf("edvbcislot: startMMI()\n"); + eDebug("edvbcislot: startMMI()"); if(application_manager) application_manager->startMMI(); @@ -424,7 +966,7 @@ int eDVBCISlot::startMMI() int eDVBCISlot::stopMMI() { - printf("edvbcislot: stopMMI()\n"); + eDebug("edvbcislot: stopMMI()"); if(mmi_session) mmi_session->stopMMI(); @@ -434,7 +976,7 @@ int eDVBCISlot::stopMMI() int eDVBCISlot::answerText(int answer) { - printf("edvbcislot: answerText(%d)\n", answer); + eDebug("edvbcislot: answerText(%d)", answer); if(mmi_session) mmi_session->answerText(answer); @@ -452,13 +994,17 @@ int eDVBCISlot::getMMIState() int eDVBCISlot::answerEnq(char *value) { - printf("edvbcislot: answerENQ(%s)\n", value); + eDebug("edvbcislot: answerENQ(%s)", value); + + if(mmi_session) + mmi_session->answerEnq(value); + return 0; } int eDVBCISlot::cancelEnq() { - printf("edvbcislot: cancelENQ\n"); + eDebug("edvbcislot: cancelENQ"); if(mmi_session) mmi_session->cancelEnq(); @@ -482,18 +1028,34 @@ int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vectorgetSpec(table_spec); int pmt_version = table_spec.version & 0x1F; // just 5 bits - if ( pmt_version == prev_sent_capmt_version ) + + eServiceReferenceDVB ref; + pmthandler->getServiceReference(ref); + uint16_t program_number = ref.getServiceID().get(); + std::map::iterator it = + running_services.find(program_number); + + if ( it != running_services.end() && + (pmt_version == it->second) && + !(caids.size() == 1 && caids[0] == 0xFFFF) ) { - eDebug("[eDVBCISlot] dont sent self capmt version twice"); + eDebug("[eDVBCISlot] dont send self capmt version twice"); return -1; } + std::vector::const_iterator i=ptr->getSections().begin(); if ( i == ptr->getSections().end() ) return -1; else { unsigned char raw_data[2048]; - CaProgramMapSection capmt(*i++, prev_sent_capmt_version != 0xFF ? 0x05 /*update*/ : 0x03 /*only*/, 0x01, caids ); + +// eDebug("send %s capmt for service %04x to slot %d", +// it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD", +// program_number, slotid); + + CaProgramMapSection capmt(*i++, + it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids ); while( i != ptr->getSections().end() ) { // eDebug("append"); @@ -521,39 +1083,92 @@ int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vectorsendCAPMT(raw_data + hlen, wp - hlen); - prev_sent_capmt_version = pmt_version; + running_services[program_number] = pmt_version; } } return 0; } -int eDVBCISlot::enableTS(int enable) +void eDVBCISlot::removeService(uint16_t program_number) { - printf("eDVBCISlot::enableTS(%d)\n", enable); - - FILE *f; - if((f = fopen("/proc/stb/tsmux/input0", "wb")) == NULL) { - printf("cannot open /proc/stb/tsmux/input0\n"); - return 0; - } - - fprintf(f, "%s", enable?"CI":"A"); - - fclose(f); - - return 0; + if (program_number == 0xFFFF) + running_services.clear(); // remove all + else + running_services.erase(program_number); // remove single service } -void eDVBCISlot::resendCAPMT() +int eDVBCISlot::setSource(data_source source) { - eDVBCIInterfaces::getInstance()->sendCAPMT(slotid); + current_source = source; + if (eDVBCIInterfaces::getInstance()->getNumOfSlots() > 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("setSource %d failed!!!\n", (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("setSource %d failed!!!\n", (int)source); + else + fprintf(ci, "%s", source==TUNER_A ? "A" : "B"); // configure CI data source (TunerA, TunerB) + fclose(ci); + } + eDebug("eDVBCISlot->setSource(%d)", (int)source); + return 0; } eAutoInitP0 init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");