4 #include <lib/base/init.h>
5 #include <lib/base/init_num.h>
6 #include <lib/base/ebase.h>
8 #include <lib/base/eerror.h>
9 #include <lib/base/nconfig.h> // access to python config
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/pmt.h>
12 #include <lib/dvb_ci/dvbci.h>
13 #include <lib/dvb_ci/dvbci_session.h>
14 #include <lib/dvb_ci/dvbci_camgr.h>
15 #include <lib/dvb_ci/dvbci_ui.h>
16 #include <lib/dvb_ci/dvbci_appmgr.h>
17 #include <lib/dvb_ci/dvbci_mmi.h>
19 #include <dvbsi++/ca_program_map_section.h>
24 #define eDebugCI(x...) eDebug(x)
26 #define eDebugCI(x...)
29 eDVBCIInterfaces *eDVBCIInterfaces::instance = 0;
31 eDVBCIInterfaces::eDVBCIInterfaces()
37 eDebug("scanning for common interfaces..");
43 sprintf(filename, "/dev/ci%d", num_ci);
45 if (stat(filename, &s))
48 ePtr<eDVBCISlot> cislot;
50 cislot = new eDVBCISlot(eApp, num_ci);
51 m_slots.push_back(cislot);
56 for (eSmartPtrList<eDVBCISlot>::iterator it(m_slots.begin()); it != m_slots.end(); ++it)
57 it->setSource(TUNER_A);
59 if (num_ci > 1) // // FIXME .. we force DM8000 when more than one CI Slot is avail
61 setInputSource(0, TUNER_A);
62 setInputSource(1, TUNER_B);
63 setInputSource(2, TUNER_C);
64 setInputSource(3, TUNER_D);
68 setInputSource(0, TUNER_A);
69 setInputSource(1, TUNER_B);
72 eDebug("done, found %d common interface slots", num_ci);
75 eDVBCIInterfaces::~eDVBCIInterfaces()
79 eDVBCIInterfaces *eDVBCIInterfaces::getInstance()
84 eDVBCISlot *eDVBCIInterfaces::getSlot(int slotid)
86 for(eSmartPtrList<eDVBCISlot>::iterator i(m_slots.begin()); i != m_slots.end(); ++i)
87 if(i->getSlotID() == slotid)
90 eDebug("FIXME: request for unknown slot");
95 int eDVBCIInterfaces::getSlotState(int slotid)
99 if( (slot = getSlot(slotid)) == 0 )
100 return eDVBCISlot::stateInvalid;
102 return slot->getState();
105 int eDVBCIInterfaces::reset(int slotid)
109 if( (slot = getSlot(slotid)) == 0 )
112 return slot->reset();
115 int eDVBCIInterfaces::initialize(int slotid)
119 if( (slot = getSlot(slotid)) == 0 )
122 slot->removeService();
124 return sendCAPMT(slotid);
127 int eDVBCIInterfaces::sendCAPMT(int slotid)
131 if( (slot = getSlot(slotid)) == 0 )
134 PMTHandlerList::iterator it = m_pmt_handlers.begin();
135 while (it != m_pmt_handlers.end())
137 eDVBCISlot *tmp = it->cislot;
138 while (tmp && tmp != slot)
139 tmp = tmp->linked_next;
142 tmp->sendCAPMT(it->pmthandler); // send capmt
151 int eDVBCIInterfaces::startMMI(int slotid)
155 if( (slot = getSlot(slotid)) == 0 )
158 return slot->startMMI();
161 int eDVBCIInterfaces::stopMMI(int slotid)
165 if( (slot = getSlot(slotid)) == 0 )
168 return slot->stopMMI();
171 int eDVBCIInterfaces::answerText(int slotid, int answer)
175 if( (slot = getSlot(slotid)) == 0 )
178 return slot->answerText(answer);
181 int eDVBCIInterfaces::answerEnq(int slotid, char *value)
185 if( (slot = getSlot(slotid)) == 0 )
188 return slot->answerEnq(value);
191 int eDVBCIInterfaces::cancelEnq(int slotid)
195 if( (slot = getSlot(slotid)) == 0 )
198 return slot->cancelEnq();
201 void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
205 eDebug("CI Slot %d: removed... usecount %d", slot->getSlotID(), slot->use_count);
206 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
207 it != m_pmt_handlers.end(); ++it)
209 if (it->cislot == slot) // remove the base slot
210 it->cislot = slot->linked_next;
213 eDVBCISlot *prevSlot = it->cislot, *hSlot = it->cislot->linked_next;
217 prevSlot->linked_next = slot->linked_next;
221 hSlot = hSlot->linked_next;
225 if (slot->linked_next)
226 slot->linked_next->setSource(slot->current_source);
227 else // last CI in chain
228 setInputSource(slot->current_tuner, slot->current_source);
229 slot->linked_next = 0;
232 slot->user_mapped=false;
233 slot->removeService(0xFFFF);
234 recheckPMTHandlers();
238 static bool canDescrambleMultipleServices(int slotid)
241 snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid);
243 ePythonConfigQuery::getConfigValue(configStr, str);
246 std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid);
247 if (appname.find("AlphaCrypt") != std::string::npos)
250 else if (str == "yes")
255 void eDVBCIInterfaces::recheckPMTHandlers()
257 eDebugCI("recheckPMTHAndlers()");
258 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
259 it != m_pmt_handlers.end(); ++it)
262 ePtr<eDVBService> service;
263 eServiceReferenceDVB ref;
264 eDVBCISlot *tmp = it->cislot;
265 eDVBServicePMTHandler *pmthandler = it->pmthandler;
266 eDVBServicePMTHandler::program p;
267 bool plugged_cis_exist = false;
269 pmthandler->getServiceReference(ref);
270 pmthandler->getService(service);
272 eDebugCI("recheck %p %s", pmthandler, ref.toString().c_str());
273 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
274 if (ci_it->plugged && ci_it->getCAManager())
276 eDebug("Slot %d plugged", ci_it->getSlotID());
277 ci_it->plugged = false;
278 plugged_cis_exist = true;
281 // check if this pmt handler has already assigned CI(s) .. and this CI(s) are already running
282 if (!plugged_cis_exist)
286 if (!tmp->running_services.empty())
288 tmp=tmp->linked_next;
290 if (tmp) // we dont like to change tsmux for running services
292 eDebugCI("already assigned and running CI!\n");
297 if (!pmthandler->getProgramInfo(p))
300 for (caidSet::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
301 caids.push_front(*x);
303 service->m_ca = caids;
307 caids = service->m_ca;
310 continue; // unscrambled service
312 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
314 eDebugCI("check Slot %d", ci_it->getSlotID());
316 bool user_mapped=true;
317 eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
322 if (!ci_it->possible_services.empty())
325 serviceSet::iterator it = ci_it->possible_services.find(ref);
326 if (it != ci_it->possible_services.end())
328 eDebug("'%s' is in service list of slot %d... so use it", ref.toString().c_str(), ci_it->getSlotID());
333 eServiceReferenceDVB parent_ref = ref.getParentServiceReference();
336 it = ci_it->possible_services.find(ref);
337 if (it != ci_it->possible_services.end())
339 eDebug("parent '%s' of '%s' is in service list of slot %d... so use it",
340 parent_ref.toString().c_str(), ref.toString().c_str(), ci_it->getSlotID());
346 if (!useThis && !ci_it->possible_providers.empty())
348 eDVBNamespace ns = ref.getDVBNamespace();
350 if (!service) // subservice?
352 eServiceReferenceDVB parent_ref = ref.getParentServiceReference();
353 eDVBDB::getInstance()->getService(parent_ref, service);
357 providerSet::iterator it = ci_it->possible_providers.find(providerPair(service->m_provider_name, ns.get()));
358 if (it != ci_it->possible_providers.end())
360 eDebug("'%s/%08x' is in provider list of slot %d... so use it", service->m_provider_name.c_str(), ns.get(), ci_it->getSlotID());
365 if (!useThis && !ci_it->possible_caids.empty())
368 for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
370 caidSet::iterator it = ci_it->possible_caids.find(*ca);
371 if (it != ci_it->possible_caids.end())
373 eDebug("caid '%04x' is in caid list of slot %d... so use it", *ca, ci_it->getSlotID());
379 if (!useThis && !mask)
381 const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
382 for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
384 std::vector<uint16_t>::const_iterator z =
385 std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
386 if ( z != ci_caids.end() && *z == *ca )
388 eDebug("The CI in Slot %d has said it can handle caid %04x... so use it", ci_it->getSlotID(), *z);
399 // check if this CI is already assigned to this pmthandler
400 eDVBCISlot *tmp = it->cislot;
405 tmp=tmp->linked_next;
407 if (tmp) // ignore already assigned cislots...
409 eDebugCI("already assigned!");
412 eDebugCI("current slot %d usecount %d", ci_it->getSlotID(), ci_it->use_count);
413 if (ci_it->use_count) // check if this CI can descramble more than one service
417 PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
418 while (!found && tmp != m_pmt_handlers.end())
421 eDVBCISlot *tmp_cislot = tmp->cislot;
422 while (!found && tmp_cislot)
425 eServiceReferenceDVB ref2;
426 tmp->pmthandler->getServiceReference(ref2);
427 if ( tmp_cislot == ci_it && it->pmthandler != tmp->pmthandler )
429 eDebugCI("check pmthandler %s for same service/tp", ref2.toString().c_str());
430 eDVBChannelID s1, s2;
433 eDebugCI("different services!");
434 ref.getChannelID(s1);
435 ref2.getChannelID(s2);
437 if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(tmp_cislot->getSlotID())))
441 eDVBCISlot *tmpci = it->cislot = tmp->cislot;
445 eDebug("(2)CISlot %d, usecount now %d", tmpci->getSlotID(), tmpci->use_count);
446 tmpci=tmpci->linked_next;
450 tmp_cislot=tmp_cislot->linked_next;
459 if (ci_it->user_mapped) // we dont like to link user mapped CIs
461 eDebugCI("user mapped CI already in use... dont link!");
466 eDebug("(1)CISlot %d, usecount now %d", ci_it->getSlotID(), ci_it->use_count);
468 data_source ci_source=CI_A;
469 switch(ci_it->getSlotID())
471 case 0: ci_source = CI_A; break;
472 case 1: ci_source = CI_B; break;
473 case 2: ci_source = CI_C; break;
474 case 3: ci_source = CI_D; break;
476 eDebug("try to get source for CI %d!!\n", ci_it->getSlotID());
483 eUsePtr<iDVBChannel> channel;
484 if (!pmthandler->getChannel(channel))
486 ePtr<iDVBFrontend> frontend;
487 if (!channel->getFrontend(frontend))
489 eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
490 tunernum = fe->getSlotID();
493 ASSERT(tunernum != -1);
494 data_source tuner_source = TUNER_A;
497 case 0: tuner_source = TUNER_A; break;
498 case 1: tuner_source = TUNER_B; break;
499 case 2: tuner_source = TUNER_C; break;
500 case 3: tuner_source = TUNER_D; break;
502 eDebug("try to get source for tuner %d!!\n", tunernum);
505 ci_it->current_tuner = tunernum;
506 setInputSource(tunernum, ci_source);
507 ci_it->setSource(tuner_source);
511 ci_it->current_tuner = it->cislot->current_tuner;
512 ci_it->linked_next = it->cislot;
513 ci_it->setSource(ci_it->linked_next->current_source);
514 ci_it->linked_next->setSource(ci_source);
517 eDebugCI("assigned!");
521 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
523 eDebugCI("user mapped CI assigned... dont link CIs!");
531 void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
533 // check if this pmthandler is already registered
534 PMTHandlerList::iterator it = m_pmt_handlers.begin();
535 while (it != m_pmt_handlers.end())
537 if ( *it++ == pmthandler )
541 eServiceReferenceDVB ref;
542 pmthandler->getServiceReference(ref);
543 eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
545 m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
546 recheckPMTHandlers();
549 void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
551 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
552 if (it != m_pmt_handlers.end())
554 eDVBCISlot *slot = it->cislot;
555 eDVBCISlot *base_slot = slot;
556 eDVBServicePMTHandler *pmthandler = it->pmthandler;
557 m_pmt_handlers.erase(it);
559 eServiceReferenceDVB service_to_remove;
560 pmthandler->getServiceReference(service_to_remove);
562 bool sameServiceExist=false;
563 for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
567 eServiceReferenceDVB ref;
568 i->pmthandler->getServiceReference(ref);
569 if ( ref == service_to_remove )
571 sameServiceExist=true;
579 eDVBCISlot *next = slot->linked_next;
580 if (!sameServiceExist)
582 eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt",
583 service_to_remove.toString().c_str());
584 std::vector<uint16_t> caids;
585 caids.push_back(0xFFFF);
586 slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service
587 slot->removeService(service_to_remove.getServiceID().get());
590 if (!--slot->use_count)
592 if (slot->linked_next)
593 slot->linked_next->setSource(slot->current_source);
595 setInputSource(slot->current_tuner, slot->current_source);
597 if (base_slot != slot)
599 eDVBCISlot *tmp = it->cislot;
600 while(tmp->linked_next != slot)
601 tmp = tmp->linked_next;
603 if (slot->linked_next)
604 tmp->linked_next = slot->linked_next;
606 tmp->linked_next = 0;
608 slot->linked_next = 0;
609 slot->user_mapped = false;
611 eDebug("(3) slot %d usecount is now %d", slot->getSlotID(), slot->use_count);
614 // check if another service is waiting for the CI
615 recheckPMTHandlers();
619 void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
621 eDebug("[eDVBCIInterfaces] gotPMT");
622 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
623 if (it != m_pmt_handlers.end() && it->cislot)
625 eDVBCISlot *tmp = it->cislot;
628 eDebugCI("check slot %d %d %d", tmp->getSlotID(), tmp->running_services.empty(), canDescrambleMultipleServices(tmp->getSlotID()));
629 if (tmp->running_services.empty() || canDescrambleMultipleServices(tmp->getSlotID()))
630 tmp->sendCAPMT(pmthandler);
631 tmp = tmp->linked_next;
636 int eDVBCIInterfaces::getMMIState(int slotid)
640 if( (slot = getSlot(slotid)) == 0 )
643 return slot->getMMIState();
646 int eDVBCIInterfaces::setInputSource(int tuner_no, data_source source)
648 // eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
649 // eDebug("eDVBCIInterfaces::setInputSource(%d %d)", tuner_no, (int)source);
650 if (getNumOfSlots() > 1) // FIXME .. we force DM8000 when more than one CI Slot is avail
653 snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
656 if((input = fopen(buf, "wb")) == NULL) {
657 eDebug("cannot open %s", buf);
662 eDebug("setInputSource(%d, %d) failed... dm8000 just have four inputs", tuner_no, (int)source);
667 fprintf(input, "CI0");
670 fprintf(input, "CI1");
673 fprintf(input, "CI2");
676 fprintf(input, "CI3");
691 eDebug("setInputSource for input %d failed!!!\n", (int)source);
700 snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
703 eDebug("setInputSource(%d, %d) failed... dm7025 just have two inputs", tuner_no, (int)source);
706 if((input = fopen(buf, "wb")) == NULL) {
707 eDebug("cannot open %s", buf);
714 fprintf(input, "CI");
723 eDebug("setInputSource for input %d failed!!!\n", (int)source);
729 eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source);
733 PyObject *eDVBCIInterfaces::getDescrambleRules(int slotid)
735 eDVBCISlot *slot = getSlot(slotid);
739 snprintf(tmp, 255, "eDVBCIInterfaces::getDescrambleRules try to get rules for CI Slot %d... but just %d slots are available", slotid, m_slots.size());
740 PyErr_SetString(PyExc_StandardError, tmp);
743 ePyObject tuple = PyTuple_New(3);
744 int caids = slot->possible_caids.size();
745 int services = slot->possible_services.size();
746 int providers = slot->possible_providers.size();
747 ePyObject caid_list = PyList_New(caids);
748 ePyObject service_list = PyList_New(services);
749 ePyObject provider_list = PyList_New(providers);
750 caidSet::iterator caid_it(slot->possible_caids.begin());
754 PyList_SET_ITEM(caid_list, caids, PyLong_FromLong(*caid_it));
757 serviceSet::iterator ref_it(slot->possible_services.begin());
761 PyList_SET_ITEM(service_list, services, PyString_FromString(ref_it->toString().c_str()));
764 providerSet::iterator provider_it(slot->possible_providers.begin());
767 ePyObject tuple = PyTuple_New(2);
768 PyTuple_SET_ITEM(tuple, 0, PyString_FromString(provider_it->first.c_str()));
769 PyTuple_SET_ITEM(tuple, 1, PyLong_FromUnsignedLong(provider_it->second));
771 PyList_SET_ITEM(provider_list, providers, tuple);
774 PyTuple_SET_ITEM(tuple, 0, service_list);
775 PyTuple_SET_ITEM(tuple, 1, provider_list);
776 PyTuple_SET_ITEM(tuple, 2, caid_list);
780 const char *PyObject_TypeStr(PyObject *o)
782 return o->ob_type && o->ob_type->tp_name ? o->ob_type->tp_name : "unknown object type";
785 RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) obj )
787 eDVBCISlot *slot = getSlot(slotid);
791 snprintf(tmp, 255, "eDVBCIInterfaces::setDescrambleRules try to set rules for CI Slot %d... but just %d slots are available", slotid, m_slots.size());
792 PyErr_SetString(PyExc_StandardError, tmp);
795 if (!PyTuple_Check(obj))
798 snprintf(tmp, 255, "2nd argument of setDescrambleRules is not a tuple.. it is a '%s'!!", PyObject_TypeStr(obj));
799 PyErr_SetString(PyExc_StandardError, tmp);
802 if (PyTuple_Size(obj) != 3)
804 const char *errstr = "eDVBCIInterfaces::setDescrambleRules not enough entrys in argument tuple!!\n"
805 "first argument should be a pythonlist with possible services\n"
806 "second argument should be a pythonlist with possible providers/dvbnamespace tuples\n"
807 "third argument should be a pythonlist with possible caids";
808 PyErr_SetString(PyExc_StandardError, errstr);
811 ePyObject service_list = PyTuple_GET_ITEM(obj, 0);
812 ePyObject provider_list = PyTuple_GET_ITEM(obj, 1);
813 ePyObject caid_list = PyTuple_GET_ITEM(obj, 2);
814 if (!PyList_Check(service_list) || !PyList_Check(provider_list) || !PyList_Check(caid_list))
817 snprintf(errstr, 512, "eDVBCIInterfaces::setDescrambleRules incorrect data types in argument tuple!!\n"
818 "first argument(%s) should be a pythonlist with possible services (reference strings)\n"
819 "second argument(%s) should be a pythonlist with possible providers (providername strings)\n"
820 "third argument(%s) should be a pythonlist with possible caids (ints)",
821 PyObject_TypeStr(service_list), PyObject_TypeStr(provider_list), PyObject_TypeStr(caid_list));
822 PyErr_SetString(PyExc_StandardError, errstr);
825 slot->possible_caids.clear();
826 slot->possible_services.clear();
827 slot->possible_providers.clear();
828 int size = PyList_Size(service_list);
832 ePyObject refstr = PyList_GET_ITEM(service_list, size);
833 if (!PyString_Check(refstr))
836 snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in service list is not a string.. it is '%s'!!", PyObject_TypeStr(refstr));
837 PyErr_SetString(PyExc_StandardError, buf);
840 char *tmpstr = PyString_AS_STRING(refstr);
841 eServiceReference ref(tmpstr);
843 slot->possible_services.insert(ref);
845 eDebug("eDVBCIInterfaces::setDescrambleRules '%s' is not a valid service reference... ignore!!", tmpstr);
847 size = PyList_Size(provider_list);
851 ePyObject tuple = PyList_GET_ITEM(provider_list, size);
852 if (!PyTuple_Check(tuple))
855 snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in provider list is not a tuple it is '%s'!!", PyObject_TypeStr(tuple));
856 PyErr_SetString(PyExc_StandardError, buf);
859 if (PyTuple_Size(tuple) != 2)
862 snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules provider tuple has %d instead of 2 entries!!", PyTuple_Size(tuple));
863 PyErr_SetString(PyExc_StandardError, buf);
866 if (!PyString_Check(PyTuple_GET_ITEM(tuple, 0)))
869 snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules 1st entry in provider tuple is not a string it is '%s'", PyObject_TypeStr(PyTuple_GET_ITEM(tuple, 0)));
870 PyErr_SetString(PyExc_StandardError, buf);
873 if (!PyLong_Check(PyTuple_GET_ITEM(tuple, 1)))
876 snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules 2nd entry in provider tuple is not a long it is '%s'", PyObject_TypeStr(PyTuple_GET_ITEM(tuple, 1)));
877 PyErr_SetString(PyExc_StandardError, buf);
880 char *tmpstr = PyString_AS_STRING(PyTuple_GET_ITEM(tuple, 0));
881 uint32_t orbpos = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(tuple, 1));
883 slot->possible_providers.insert(std::pair<std::string, uint32_t>(tmpstr, orbpos));
885 eDebug("eDVBCIInterfaces::setDescrambleRules ignore invalid entry in provider tuple (string is empty)!!");
887 size = PyList_Size(caid_list);
891 ePyObject caid = PyList_GET_ITEM(caid_list, size);
892 if (!PyLong_Check(caid))
895 snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in caid list is not a long it is '%s'!!", PyObject_TypeStr(caid));
896 PyErr_SetString(PyExc_StandardError, buf);
899 int tmpcaid = PyLong_AsLong(caid);
900 if (tmpcaid > 0 && tmpcaid < 0x10000)
901 slot->possible_caids.insert(tmpcaid);
903 eDebug("eDVBCIInterfaces::setDescrambleRules %d is not a valid caid... ignore!!", tmpcaid);
908 PyObject *eDVBCIInterfaces::readCICaIds(int slotid)
910 eDVBCISlot *slot = getSlot(slotid);
914 snprintf(tmp, 255, "eDVBCIInterfaces::readCICaIds try to get CAIds for CI Slot %d... but just %d slots are available", slotid, m_slots.size());
915 PyErr_SetString(PyExc_StandardError, tmp);
920 eDVBCICAManagerSession *ca_manager = slot->getCAManager();
921 const std::vector<uint16_t> *ci_caids = ca_manager ? &ca_manager->getCAIDs() : 0;
922 ePyObject list = PyList_New(ci_caids ? ci_caids->size() : 0);
925 for (std::vector<uint16_t>::const_iterator it = ci_caids->begin(); it != ci_caids->end(); ++it)
926 PyList_SET_ITEM(list, idx++, PyLong_FromLong(*it));
933 int eDVBCIInterfaces::setCIClockRate(int slotid, int rate)
935 eDVBCISlot *slot = getSlot(slotid);
937 return slot->setClockRate(rate);
941 int eDVBCISlot::send(const unsigned char *data, size_t len)
945 //eDebugNoNewLine("< ");
947 // eDebugNoNewLine("%02x ",data[i]);
950 if (sendqueue.empty())
951 res = ::write(fd, data, len);
953 if (res < 0 || (unsigned int)res != len)
955 unsigned char *d = new unsigned char[len];
956 memcpy(d, data, len);
957 sendqueue.push( queueData(d, len) );
958 notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
964 void eDVBCISlot::data(int what)
966 eDebugCI("CISlot %d what %d\n", getSlotID(), what);
967 if(what == eSocketNotifier::Priority) {
968 if(state != stateRemoved) {
969 state = stateRemoved;
970 while(sendqueue.size())
972 delete [] sendqueue.top().data;
975 eDVBCISession::deleteSessions(this);
976 eDVBCIInterfaces::getInstance()->ciRemoved(this);
977 notifier->setRequested(eSocketNotifier::Read);
978 eDVBCI_UI::getInstance()->setState(getSlotID(),0);
983 if (state == stateInvalid)
986 if(state != stateInserted) {
987 eDebug("ci inserted in slot %d", getSlotID());
988 state = stateInserted;
989 eDVBCI_UI::getInstance()->setState(getSlotID(),1);
990 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
991 /* enable PRI to detect removal or errors */
994 if (what & eSocketNotifier::Read) {
997 r = ::read(fd, data, 4096);
1000 // eDebugNoNewLine("> ");
1002 // eDebugNoNewLine("%02x ",data[i]);
1004 eDVBCISession::receiveData(this, data, r);
1005 eDVBCISession::pollAll();
1009 else if (what & eSocketNotifier::Write) {
1010 if (!sendqueue.empty()) {
1011 const queueData &qe = sendqueue.top();
1012 int res = ::write(fd, qe.data, qe.len);
1013 if (res >= 0 && (unsigned int)res == qe.len)
1020 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
1024 DEFINE_REF(eDVBCISlot);
1026 eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
1030 application_manager = 0;
1035 user_mapped = false;
1040 sprintf(filename, "/dev/ci%d", nr);
1042 // possible_caids.insert(0x1702);
1043 // possible_providers.insert(providerPair("PREMIERE", 0xC00000));
1044 // possible_services.insert(eServiceReference("1:0:1:2A:4:85:C00000:0:0:0:"));
1046 fd = ::open(filename, O_RDWR | O_NONBLOCK);
1048 eDebugCI("CI Slot %d has fd %d", getSlotID(), fd);
1049 state = stateInvalid;
1053 notifier = eSocketNotifier::create(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
1054 CONNECT(notifier->activated, eDVBCISlot::data);
1061 eDVBCISlot::~eDVBCISlot()
1063 eDVBCISession::deleteSessions(this);
1066 void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
1068 application_manager=session;
1071 void eDVBCISlot::setMMIManager( eDVBCIMMISession *session )
1073 mmi_session = session;
1076 void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session )
1078 ca_manager = session;
1081 int eDVBCISlot::getSlotID()
1086 int eDVBCISlot::reset()
1088 eDebug("CI Slot %d: reset requested", getSlotID());
1090 if (state == stateInvalid)
1092 unsigned char buf[256];
1094 while(::read(fd, buf, 256)>0);
1095 state = stateResetted;
1098 while(sendqueue.size())
1100 delete [] sendqueue.top().data;
1109 int eDVBCISlot::startMMI()
1111 eDebug("CI Slot %d: startMMI()", getSlotID());
1113 if(application_manager)
1114 application_manager->startMMI();
1119 int eDVBCISlot::stopMMI()
1121 eDebug("CI Slot %d: stopMMI()", getSlotID());
1124 mmi_session->stopMMI();
1129 int eDVBCISlot::answerText(int answer)
1131 eDebug("CI Slot %d: answerText(%d)", getSlotID(), answer);
1134 mmi_session->answerText(answer);
1139 int eDVBCISlot::getMMIState()
1147 int eDVBCISlot::answerEnq(char *value)
1149 eDebug("CI Slot %d: answerENQ(%s)", getSlotID(), value);
1152 mmi_session->answerEnq(value);
1157 int eDVBCISlot::cancelEnq()
1159 eDebug("CI Slot %d: cancelENQ", getSlotID());
1162 mmi_session->cancelEnq();
1167 int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
1171 eDebug("no ca_manager (no CI plugged?)");
1174 const std::vector<uint16_t> &caids = ids.empty() ? ca_manager->getCAIDs() : ids;
1175 ePtr<eTable<ProgramMapSection> > ptr;
1176 if (pmthandler->getPMT(ptr))
1180 eDVBTableSpec table_spec;
1181 ptr->getSpec(table_spec);
1182 int pmt_version = table_spec.version & 0x1F; // just 5 bits
1184 eServiceReferenceDVB ref;
1185 pmthandler->getServiceReference(ref);
1186 uint16_t program_number = ref.getServiceID().get();
1187 std::map<uint16_t, uint8_t>::iterator it =
1188 running_services.find(program_number);
1190 if ( it != running_services.end() &&
1191 (pmt_version == it->second) &&
1192 !(caids.size() == 1 && caids[0] == 0xFFFF) )
1194 eDebug("[eDVBCISlot] dont send self capmt version twice");
1198 std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
1199 if ( i == ptr->getSections().end() )
1203 unsigned char raw_data[2048];
1205 // eDebug("send %s capmt for service %04x to slot %d",
1206 // it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
1207 // program_number, slotid);
1209 CaProgramMapSection capmt(*i++,
1210 it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids );
1211 while( i != ptr->getSections().end() )
1213 // eDebug("append");
1216 capmt.writeToBuffer(raw_data);
1218 // begin calc capmt length
1221 if ( raw_data[3] & 0x80 )
1224 int lenbytes = raw_data[3] & ~0x80;
1226 wp = (wp << 8) | raw_data[4 + i++];
1229 hlen = 4 + lenbytes;
1237 // end calc capmt length
1238 // eDebug("ca_manager %p dump capmt:", ca_manager);
1239 // for(int i=0;i<wp;i++)
1240 // eDebugNoNewLine("%02x ", raw_data[i]);
1243 if (caids.size() == 1 && caids[0] == 0xFFFF)
1245 // eDebugNoNewLine("SEND EMPTY CAPMT.. old version is %02x", raw_data[hlen+3]);
1246 raw_data[hlen+3] &= ~0x3E;
1247 raw_data[hlen+3] |= ((pmt_version+1) & 0x1F) << 1;
1248 // eDebug(" new version is %02x", raw_data[hlen+3]);
1251 //dont need tag and lenfield
1252 ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
1253 running_services[program_number] = pmt_version;
1259 void eDVBCISlot::removeService(uint16_t program_number)
1261 if (program_number == 0xFFFF)
1262 running_services.clear(); // remove all
1264 running_services.erase(program_number); // remove single service
1267 int eDVBCISlot::setSource(data_source source)
1269 current_source = source;
1270 if (eDVBCIInterfaces::getInstance()->getNumOfSlots() > 1) // FIXME .. we force DM8000 when more than one CI Slot is avail
1273 snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slotid);
1274 FILE *ci = fopen(buf, "wb");
1302 eDebug("CI Slot %d: setSource %d failed!!!\n", getSlotID(), (int)source);
1309 // eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
1310 // eDebug("eDVBCISlot::enableTS(%d %d)", enable, (int)source);
1311 FILE *ci = fopen("/proc/stb/tsmux/input2", "wb");
1313 eDebug("cannot open /proc/stb/tsmux/input2");
1316 if (source != TUNER_A && source != TUNER_B)
1317 eDebug("CI Slot %d: setSource %d failed!!!\n", getSlotID(), (int)source);
1319 fprintf(ci, "%s", source==TUNER_A ? "A" : "B"); // configure CI data source (TunerA, TunerB)
1322 eDebug("CI Slot %d setSource(%d)", getSlotID(), (int)source);
1326 int eDVBCISlot::setClockRate(int rate)
1329 snprintf(buf, 64, "/proc/stb/tsmux/ci%d_tsclk", slotid);
1330 FILE *ci = fopen(buf, "wb");
1334 fprintf(ci, "high");
1336 fprintf(ci, "normal");
1343 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");