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/pmt.h>
11 #include <lib/dvb_ci/dvbci.h>
12 #include <lib/dvb_ci/dvbci_session.h>
13 #include <lib/dvb_ci/dvbci_camgr.h>
14 #include <lib/dvb_ci/dvbci_ui.h>
15 #include <lib/dvb_ci/dvbci_appmgr.h>
16 #include <lib/dvb_ci/dvbci_mmi.h>
18 #include <dvbsi++/ca_program_map_section.h>
20 eDVBCIInterfaces *eDVBCIInterfaces::instance = 0;
22 eDVBCIInterfaces::eDVBCIInterfaces()
28 eDebug("scanning for common interfaces..");
34 sprintf(filename, "/dev/ci%d", num_ci);
36 if (stat(filename, &s))
39 ePtr<eDVBCISlot> cislot;
41 cislot = new eDVBCISlot(eApp, num_ci);
42 m_slots.push_back(cislot);
47 eDebug("done, found %d common interface slots", num_ci);
50 eDVBCIInterfaces::~eDVBCIInterfaces()
54 eDVBCIInterfaces *eDVBCIInterfaces::getInstance()
59 eDVBCISlot *eDVBCIInterfaces::getSlot(int slotid)
61 for(eSmartPtrList<eDVBCISlot>::iterator i(m_slots.begin()); i != m_slots.end(); ++i)
62 if(i->getSlotID() == slotid)
65 eDebug("FIXME: request for unknown slot");
70 int eDVBCIInterfaces::getSlotState(int slotid)
74 if( (slot = getSlot(slotid)) == 0 )
75 return eDVBCISlot::stateInvalid;
77 return slot->getState();
80 int eDVBCIInterfaces::reset(int slotid)
84 if( (slot = getSlot(slotid)) == 0 )
87 eDVBCISession::deleteSessions(slot);
93 int eDVBCIInterfaces::initialize(int slotid)
97 if( (slot = getSlot(slotid)) == 0 )
100 slot->removeService();
102 return sendCAPMT(slotid);
105 int eDVBCIInterfaces::sendCAPMT(int slotid)
109 if( (slot = getSlot(slotid)) == 0 )
112 PMTHandlerList::iterator it = m_pmt_handlers.begin();
113 while (it != m_pmt_handlers.end())
115 eDVBCISlot *tmp = it->cislot;
117 tmp = tmp->linked_next;
120 tmp->sendCAPMT(it->pmthandler); // send capmt
129 int eDVBCIInterfaces::startMMI(int slotid)
133 if( (slot = getSlot(slotid)) == 0 )
136 return slot->startMMI();
139 int eDVBCIInterfaces::stopMMI(int slotid)
143 if( (slot = getSlot(slotid)) == 0 )
146 return slot->stopMMI();
149 int eDVBCIInterfaces::answerText(int slotid, int answer)
153 if( (slot = getSlot(slotid)) == 0 )
156 return slot->answerText(answer);
159 int eDVBCIInterfaces::answerEnq(int slotid, char *value)
163 if( (slot = getSlot(slotid)) == 0 )
166 return slot->answerEnq(value);
169 int eDVBCIInterfaces::cancelEnq(int slotid)
173 if( (slot = getSlot(slotid)) == 0 )
176 return slot->cancelEnq();
179 void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
181 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
182 it != m_pmt_handlers.end(); ++it)
184 eServiceReferenceDVB ref;
185 it->pmthandler->getServiceReference(ref);
186 slot->removeService(ref.getServiceID().get());
187 if (slot->use_count && !--slot->use_count)
189 if (slot->linked_next)
190 slot->linked_next->setSource(slot->current_source);
192 setInputSource(slot->current_tuner, slot->current_source);
194 if (it->cislot == slot) // remove the base slot
195 it->cislot = slot->linked_next;
198 if (slot->linked_next)
200 eDVBCISlot *tmp = it->cislot;
201 while(tmp->linked_next != slot)
202 tmp = tmp->linked_next;
204 tmp->linked_next = slot->linked_next;
212 static bool canDescrambleMultipleServices(int slotid)
215 snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid);
217 ePythonConfigQuery::getConfigValue(configStr, str);
220 std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid);
221 if (appname.find("AlphaCrypt") != std::string::npos)
224 else if (str == "yes")
229 void eDVBCIInterfaces::recheckPMTHandlers()
231 // eDebug("recheckPMTHAndlers()");
232 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
233 it != m_pmt_handlers.end(); ++it)
236 ePtr<eDVBService> service;
237 eServiceReferenceDVB ref;
238 eDVBServicePMTHandler *pmthandler = it->pmthandler;
239 eDVBServicePMTHandler::program p;
241 pmthandler->getServiceReference(ref);
242 pmthandler->getService(service);
243 if (!pmthandler->getProgramInfo(p))
246 for (std::set<uint16_t>::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
247 caids.push_front(*x);
249 service->m_ca = caids;
253 caids = service->m_ca;
257 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
260 eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
263 const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
264 for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
266 std::vector<uint16_t>::const_iterator z =
267 std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
268 if ( z != ci_caids.end() && *z == *ca )
270 // eDebug("found ci for caid %04x", *z);
279 if (ci_it->use_count) // check if this CI can descramble more than one service
282 PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
283 while (tmp != m_pmt_handlers.end())
285 if ( tmp->cislot == ci_it && it != tmp )
287 eServiceReferenceDVB ref2;
288 tmp->pmthandler->getServiceReference(ref2);
289 eDVBChannelID s1, s2;
292 ref.getChannelID(s1);
293 ref2.getChannelID(s2);
295 if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(ci_it->getSlotID())))
306 // check if this CI is already assigned to this pmthandler
307 eDVBCISlot *tmp = it->cislot;
314 if (tmp) // ignore already assigned cislots...
318 // eDebug("usecount now %d", ci_it->use_count);
320 data_source ci_source=CI_A;
321 switch(ci_it->getSlotID())
323 case 0: ci_source = CI_A; break;
324 case 1: ci_source = CI_B; break;
325 case 2: ci_source = CI_C; break;
326 case 3: ci_source = CI_D; break;
328 eDebug("try to get source for CI %d!!\n", ci_it->getSlotID());
335 eUsePtr<iDVBChannel> channel;
336 if (!pmthandler->getChannel(channel))
338 ePtr<iDVBFrontend> frontend;
339 if (!channel->getFrontend(frontend))
341 eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
342 tunernum = fe->getID();
345 ASSERT(tunernum != -1);
346 data_source tuner_source = TUNER_A;
349 case 0: tuner_source = TUNER_A; break;
350 case 1: tuner_source = TUNER_B; break;
351 case 2: tuner_source = TUNER_C; break;
352 case 3: tuner_source = TUNER_D; break;
354 eDebug("try to get source for tuner %d!!\n", tunernum);
357 ci_it->current_tuner = tunernum;
358 setInputSource(tunernum, ci_source);
359 ci_it->setSource(tuner_source);
363 ci_it->current_tuner = it->cislot->current_tuner;
364 ci_it->linked_next = it->cislot;
365 ci_it->setSource(ci_it->linked_next->current_source);
366 ci_it->linked_next->setSource(ci_source);
377 void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
379 // check if this pmthandler is already registered
380 PMTHandlerList::iterator it = m_pmt_handlers.begin();
381 while (it != m_pmt_handlers.end())
383 if ( *it++ == pmthandler )
387 eServiceReferenceDVB ref;
388 pmthandler->getServiceReference(ref);
389 eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
391 m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
392 recheckPMTHandlers();
395 void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
397 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
398 if (it != m_pmt_handlers.end())
400 eDVBCISlot *slot = it->cislot;
401 eDVBServicePMTHandler *pmthandler = it->pmthandler;
402 m_pmt_handlers.erase(it);
404 eServiceReferenceDVB service_to_remove;
405 pmthandler->getServiceReference(service_to_remove);
407 bool sameServiceExist=false;
408 for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
412 eServiceReferenceDVB ref;
413 i->pmthandler->getServiceReference(ref);
414 if ( ref == service_to_remove )
416 sameServiceExist=true;
424 if (!sameServiceExist)
426 if (slot->getNumOfServices() > 1)
428 eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt",
429 service_to_remove.toString().c_str());
430 std::vector<uint16_t> caids;
431 caids.push_back(0xFFFF);
432 slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service
434 slot->removeService(service_to_remove.getServiceID().get());
437 eDVBCISlot *next = slot->linked_next;
438 if (!--slot->use_count)
440 if (slot->linked_next)
441 slot->linked_next->setSource(slot->current_source);
443 setInputSource(slot->current_tuner, slot->current_source);
445 if (it->cislot == slot) // remove the base slot
446 it->cislot = slot->linked_next;
449 if (slot->linked_next)
451 eDVBCISlot *tmp = it->cislot;
452 while(tmp->linked_next != slot)
453 tmp = tmp->linked_next;
455 tmp->linked_next = slot->linked_next;
460 // eDebug("use_count is now %d", slot->use_count);
464 // check if another service is waiting for the CI
465 recheckPMTHandlers();
468 void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
470 eDebug("[eDVBCIInterfaces] gotPMT");
471 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
472 if (it != m_pmt_handlers.end() && it->cislot)
474 eDVBCISlot *tmp = it->cislot;
477 tmp->sendCAPMT(pmthandler);
478 tmp = tmp->linked_next;
483 int eDVBCIInterfaces::getMMIState(int slotid)
487 if( (slot = getSlot(slotid)) == 0 )
490 return slot->getMMIState();
493 int eDVBCIInterfaces::setInputSource(int tuner_no, data_source source)
495 // eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
496 // eDebug("eDVBCIInterfaces::setInputSource(%d %d)", tuner_no, (int)source);
499 snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
502 if((input = fopen(buf, "wb")) == NULL) {
503 eDebug("cannot open %s", buf);
508 eDebug("setInputSource(%d, %d) failed... dm8000 just have four inputs", tuner_no, (int)source);
513 fprintf(input, "CI0");
516 fprintf(input, "CI1");
519 fprintf(input, "CI2");
522 fprintf(input, "CI3");
537 eDebug("setInputSource for input %d failed!!!\n", (int)source);
542 #else // force DM7025
544 snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
547 eDebug("setInputSource(%d, %d) failed... dm7025 just have two inputs", tuner_no, (int)source);
550 if((input = fopen(buf, "wb")) == NULL) {
551 eDebug("cannot open %s", buf);
558 fprintf(input, "CI");
567 eDebug("setInputSource for input %d failed!!!\n", (int)source);
573 eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source);
578 int eDVBCISlot::send(const unsigned char *data, size_t len)
582 //eDebugNoNewLine("< ");
584 // eDebugNoNewLine("%02x ",data[i]);
587 if (sendqueue.empty())
588 res = ::write(fd, data, len);
590 if (res < 0 || (unsigned int)res != len)
592 unsigned char *d = new unsigned char[len];
593 memcpy(d, data, len);
594 sendqueue.push( queueData(d, len) );
595 notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
601 void eDVBCISlot::data(int what)
603 if(what == eSocketNotifier::Priority) {
604 if(state != stateRemoved) {
605 state = stateRemoved;
606 eDebug("ci removed");
607 while(sendqueue.size())
609 delete [] sendqueue.top().data;
612 eDVBCIInterfaces::getInstance()->ciRemoved(this);
613 eDVBCISession::deleteSessions(this);
614 notifier->setRequested(eSocketNotifier::Read);
615 eDVBCI_UI::getInstance()->setState(getSlotID(),0);
620 if (state == stateInvalid)
623 if(state != stateInserted) {
624 eDebug("ci inserted");
625 state = stateInserted;
626 eDVBCI_UI::getInstance()->setState(getSlotID(),1);
627 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
628 /* enable PRI to detect removal or errors */
631 if (what & eSocketNotifier::Read) {
634 r = ::read(fd, data, 4096);
637 // eDebugNoNewLine("> ");
639 // eDebugNoNewLine("%02x ",data[i]);
641 eDVBCISession::receiveData(this, data, r);
642 eDVBCISession::pollAll();
646 else if (what & eSocketNotifier::Write) {
647 if (!sendqueue.empty()) {
648 const queueData &qe = sendqueue.top();
649 int res = ::write(fd, qe.data, qe.len);
650 if (res >= 0 && (unsigned int)res == qe.len)
657 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
661 DEFINE_REF(eDVBCISlot);
663 eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
667 application_manager = 0;
675 sprintf(filename, "/dev/ci%d", nr);
677 fd = ::open(filename, O_RDWR | O_NONBLOCK);
679 eDebug("eDVBCISlot has fd %d", fd);
680 state = stateInvalid;
684 notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
685 CONNECT(notifier->activated, eDVBCISlot::data);
692 eDVBCISlot::~eDVBCISlot()
696 void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
698 application_manager=session;
701 void eDVBCISlot::setMMIManager( eDVBCIMMISession *session )
703 mmi_session = session;
706 void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session )
708 ca_manager = session;
711 int eDVBCISlot::getSlotID()
716 int eDVBCISlot::reset()
718 eDebug("edvbcislot: reset requested");
720 if (state == stateInvalid)
722 unsigned char buf[256];
724 while(::read(fd, buf, 256)>0);
725 state = stateResetted;
728 while(sendqueue.size())
730 delete [] sendqueue.top().data;
739 int eDVBCISlot::startMMI()
741 eDebug("edvbcislot: startMMI()");
743 if(application_manager)
744 application_manager->startMMI();
749 int eDVBCISlot::stopMMI()
751 eDebug("edvbcislot: stopMMI()");
754 mmi_session->stopMMI();
759 int eDVBCISlot::answerText(int answer)
761 eDebug("edvbcislot: answerText(%d)", answer);
764 mmi_session->answerText(answer);
769 int eDVBCISlot::getMMIState()
777 int eDVBCISlot::answerEnq(char *value)
779 eDebug("edvbcislot: answerENQ(%s)", value);
782 mmi_session->answerEnq(value);
787 int eDVBCISlot::cancelEnq()
789 eDebug("edvbcislot: cancelENQ");
792 mmi_session->cancelEnq();
797 int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
801 eDebug("no ca_manager (no CI plugged?)");
804 const std::vector<uint16_t> &caids = ids.empty() ? ca_manager->getCAIDs() : ids;
805 ePtr<eTable<ProgramMapSection> > ptr;
806 if (pmthandler->getPMT(ptr))
810 eDVBTableSpec table_spec;
811 ptr->getSpec(table_spec);
812 int pmt_version = table_spec.version & 0x1F; // just 5 bits
814 eServiceReferenceDVB ref;
815 pmthandler->getServiceReference(ref);
816 uint16_t program_number = ref.getServiceID().get();
817 std::map<uint16_t, uint8_t>::iterator it =
818 running_services.find(program_number);
820 if ( it != running_services.end() &&
821 (pmt_version == it->second) &&
822 !(caids.size() == 1 && caids[0] == 0xFFFF) )
824 eDebug("[eDVBCISlot] dont send self capmt version twice");
828 std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
829 if ( i == ptr->getSections().end() )
833 unsigned char raw_data[2048];
835 // eDebug("send %s capmt for service %04x",
836 // it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
839 CaProgramMapSection capmt(*i++,
840 it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids );
841 while( i != ptr->getSections().end() )
846 capmt.writeToBuffer(raw_data);
848 // begin calc capmt length
851 if ( raw_data[3] & 0x80 )
854 int lenbytes = raw_data[3] & ~0x80;
856 wp = (wp << 8) | raw_data[4 + i++];
867 // end calc capmt length
868 // eDebug("ca_manager %p dump capmt:", ca_manager);
869 // for(int i=0;i<wp;i++)
870 // eDebugNoNewLine("%02x ", raw_data[i]);
873 if (caids.size() == 1 && caids[0] == 0xFFFF)
875 // eDebugNoNewLine("SEND EMPTY CAPMT.. old version is %02x", raw_data[hlen+3]);
876 raw_data[hlen+3] &= ~0x3E;
877 raw_data[hlen+3] |= ((pmt_version+1) & 0x1F) << 1;
878 // eDebug(" new version is %02x", raw_data[hlen+3]);
881 //dont need tag and lenfield
882 ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
883 running_services[program_number] = pmt_version;
889 void eDVBCISlot::removeService(uint16_t program_number)
891 if (program_number == 0xFFFF)
892 running_services.clear(); // remove all
894 running_services.erase(program_number); // remove single service
897 int eDVBCISlot::setSource(data_source source)
899 current_source = source;
902 snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slotid);
903 FILE *ci = fopen(buf, "wb");
931 eDebug("setSource %d failed!!!\n", (int)source);
935 #else // force DM7025
936 // eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
937 // eDebug("eDVBCISlot::enableTS(%d %d)", enable, (int)source);
938 FILE *ci = fopen("/proc/stb/tsmux/input2", "wb");
940 eDebug("cannot open /proc/stb/tsmux/input2");
943 if (source != TUNER_A && source != TUNER_B)
944 eDebug("setSource %d failed!!!\n", (int)source);
946 fprintf(ci, "%s", source==TUNER_A ? "A" : "B"); // configure CI data source (TunerA, TunerB)
949 eDebug("eDVBCISlot->setSource(%d)", (int)source);
953 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");