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::enableTS(int slotid, int enable)
97 if( (slot = getSlot(slotid)) == 0 )
101 PMTHandlerList::iterator it = m_pmt_handlers.begin();
102 while (it != m_pmt_handlers.end())
104 if ( it->cislot == slot )
106 eDVBServicePMTHandler *pmthandler = it->pmthandler;
107 eUsePtr<iDVBChannel> channel;
108 if (!pmthandler->getChannel(channel))
110 ePtr<iDVBFrontend> frontend;
111 if (!channel->getFrontend(frontend))
113 eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
114 tunernum = fe->getID();
121 return slot->enableTS(enable, tunernum);
124 int eDVBCIInterfaces::initialize(int slotid)
128 if( (slot = getSlot(slotid)) == 0 )
131 slot->removeService();
133 return sendCAPMT(slotid);
136 int eDVBCIInterfaces::sendCAPMT(int slotid)
140 if( (slot = getSlot(slotid)) == 0 )
143 PMTHandlerList::iterator it = m_pmt_handlers.begin();
144 while (it != m_pmt_handlers.end())
146 if ( it->cislot == slot )
147 slot->sendCAPMT(it->pmthandler); // send capmt
154 int eDVBCIInterfaces::startMMI(int slotid)
158 if( (slot = getSlot(slotid)) == 0 )
161 return slot->startMMI();
164 int eDVBCIInterfaces::stopMMI(int slotid)
168 if( (slot = getSlot(slotid)) == 0 )
171 return slot->stopMMI();
174 int eDVBCIInterfaces::answerText(int slotid, int answer)
178 if( (slot = getSlot(slotid)) == 0 )
181 return slot->answerText(answer);
184 int eDVBCIInterfaces::answerEnq(int slotid, char *value)
188 if( (slot = getSlot(slotid)) == 0 )
191 return slot->answerEnq(value);
194 int eDVBCIInterfaces::cancelEnq(int slotid)
198 if( (slot = getSlot(slotid)) == 0 )
201 return slot->cancelEnq();
204 void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
206 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
207 it != m_pmt_handlers.end(); ++it)
209 if (it->cislot == slot)
211 eServiceReferenceDVB ref;
212 it->pmthandler->getServiceReference(ref);
213 slot->removeService(ref.getServiceID().get());
214 if (!--slot->use_count)
215 enableTS(slot->getSlotID(), 0);
221 static bool canDescrambleMultipleServices(int slotid)
224 snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid);
226 ePythonConfigQuery::getConfigValue(configStr, str);
229 std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid);
230 if (appname.find("AlphaCrypt") != std::string::npos)
233 else if (str == "yes")
238 void eDVBCIInterfaces::recheckPMTHandlers()
240 // eDebug("recheckPMTHAndlers()");
241 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
242 it != m_pmt_handlers.end(); ++it)
245 ePtr<eDVBService> service;
246 eServiceReferenceDVB ref;
247 eDVBServicePMTHandler *pmthandler = it->pmthandler;
248 eDVBServicePMTHandler::program p;
250 pmthandler->getServiceReference(ref);
251 pmthandler->getService(service);
252 if (!pmthandler->getProgramInfo(p))
255 for (std::set<uint16_t>::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
256 caids.push_front(*x);
258 service->m_ca = caids;
262 continue; // already running
265 caids = service->m_ca;
269 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
272 eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
275 const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
276 for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
278 std::vector<uint16_t>::const_iterator z =
279 std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
280 if ( z != ci_caids.end() && *z == *ca )
282 eDebug("found ci for caid %04x", *z);
291 bool send_ca_pmt = false;
292 if (ci_it->use_count) // check if this CI can descramble more than one service
294 PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
295 while (tmp != m_pmt_handlers.end())
299 eServiceReferenceDVB ref2;
300 tmp->pmthandler->getServiceReference(ref2);
301 eDVBChannelID s1, s2;
304 ref.getChannelID(s1);
305 ref2.getChannelID(s2);
307 if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(ci_it->getSlotID())))
309 it->cislot = tmp->cislot;
310 ++it->cislot->use_count;
312 // eDebug("usecount now %d", it->cislot->use_count);
323 // eDebug("usecount now %d", it->cislot->use_count);
324 enableTS(ci_it->getSlotID(), 1);
335 void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
337 // check if this pmthandler is already registered
338 PMTHandlerList::iterator it = m_pmt_handlers.begin();
339 while (it != m_pmt_handlers.end())
341 if ( *it++ == pmthandler )
345 eServiceReferenceDVB ref;
346 pmthandler->getServiceReference(ref);
347 eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
349 m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
350 recheckPMTHandlers();
353 void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
355 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
356 if (it != m_pmt_handlers.end())
358 eDVBCISlot *slot = it->cislot;
359 eDVBServicePMTHandler *pmthandler = it->pmthandler;
360 m_pmt_handlers.erase(it);
362 eServiceReferenceDVB service_to_remove;
363 pmthandler->getServiceReference(service_to_remove);
365 bool sameServiceExist=false;
366 for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
370 eServiceReferenceDVB ref;
371 i->pmthandler->getServiceReference(ref);
372 if ( ref == service_to_remove )
374 sameServiceExist=true;
380 if (slot && !sameServiceExist)
382 if (slot->getNumOfServices() > 1)
384 eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt",
385 service_to_remove.toString().c_str());
386 std::vector<uint16_t> caids;
387 caids.push_back(0xFFFF);
388 slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service
390 slot->removeService(service_to_remove.getServiceID().get());
393 if (slot && !--slot->use_count)
395 ASSERT(!slot->getNumOfServices());
396 enableTS(slot->getSlotID(),0);
399 // check if another service is waiting for the CI
400 recheckPMTHandlers();
403 void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
405 eDebug("[eDVBCIInterfaces] gotPMT");
406 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
407 if (it != m_pmt_handlers.end() && it->cislot)
408 it->cislot->sendCAPMT(pmthandler);
411 int eDVBCIInterfaces::getMMIState(int slotid)
415 if( (slot = getSlot(slotid)) == 0 )
418 return slot->getMMIState();
421 int eDVBCISlot::send(const unsigned char *data, size_t len)
425 //eDebugNoNewLine("< ");
427 // eDebugNoNewLine("%02x ",data[i]);
430 if (sendqueue.empty())
431 res = ::write(fd, data, len);
433 if (res < 0 || (unsigned int)res != len)
435 unsigned char *d = new unsigned char[len];
436 memcpy(d, data, len);
437 sendqueue.push( queueData(d, len) );
438 notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
444 void eDVBCISlot::data(int what)
446 if(what == eSocketNotifier::Priority) {
447 if(state != stateRemoved) {
448 state = stateRemoved;
449 eDebug("ci removed");
450 while(sendqueue.size())
452 delete [] sendqueue.top().data;
455 eDVBCIInterfaces::getInstance()->ciRemoved(this);
456 eDVBCISession::deleteSessions(this);
457 notifier->setRequested(eSocketNotifier::Read);
458 eDVBCI_UI::getInstance()->setState(getSlotID(),0);
463 if (state == stateInvalid)
466 if(state != stateInserted) {
467 eDebug("ci inserted");
468 state = stateInserted;
469 eDVBCI_UI::getInstance()->setState(getSlotID(),1);
470 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
471 /* enable PRI to detect removal or errors */
474 if (what & eSocketNotifier::Read) {
477 r = ::read(fd, data, 4096);
480 // eDebugNoNewLine("> ");
482 // eDebugNoNewLine("%02x ",data[i]);
484 eDVBCISession::receiveData(this, data, r);
485 eDVBCISession::pollAll();
489 else if (what & eSocketNotifier::Write) {
490 if (!sendqueue.empty()) {
491 const queueData &qe = sendqueue.top();
492 int res = ::write(fd, qe.data, qe.len);
493 if (res >= 0 && (unsigned int)res == qe.len)
500 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
504 DEFINE_REF(eDVBCISlot);
506 eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
510 application_manager = 0;
517 sprintf(filename, "/dev/ci%d", nr);
519 fd = ::open(filename, O_RDWR | O_NONBLOCK);
521 eDebug("eDVBCISlot has fd %d", fd);
522 state = stateInvalid;
526 notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
527 CONNECT(notifier->activated, eDVBCISlot::data);
536 eDVBCISlot::~eDVBCISlot()
540 void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
542 application_manager=session;
545 void eDVBCISlot::setMMIManager( eDVBCIMMISession *session )
547 mmi_session = session;
550 void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session )
552 ca_manager = session;
555 int eDVBCISlot::getSlotID()
560 int eDVBCISlot::reset()
562 eDebug("edvbcislot: reset requested");
564 if (state == stateInvalid)
566 unsigned char buf[256];
568 while(::read(fd, buf, 256)>0);
569 state = stateResetted;
572 while(sendqueue.size())
574 delete [] sendqueue.top().data;
583 int eDVBCISlot::startMMI()
585 eDebug("edvbcislot: startMMI()");
587 if(application_manager)
588 application_manager->startMMI();
593 int eDVBCISlot::stopMMI()
595 eDebug("edvbcislot: stopMMI()");
598 mmi_session->stopMMI();
603 int eDVBCISlot::answerText(int answer)
605 eDebug("edvbcislot: answerText(%d)", answer);
608 mmi_session->answerText(answer);
613 int eDVBCISlot::getMMIState()
621 int eDVBCISlot::answerEnq(char *value)
623 eDebug("edvbcislot: answerENQ(%s)", value);
626 mmi_session->answerEnq(value);
631 int eDVBCISlot::cancelEnq()
633 eDebug("edvbcislot: cancelENQ");
636 mmi_session->cancelEnq();
641 int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
645 eDebug("no ca_manager (no CI plugged?)");
648 const std::vector<uint16_t> &caids = ids.empty() ? ca_manager->getCAIDs() : ids;
649 ePtr<eTable<ProgramMapSection> > ptr;
650 if (pmthandler->getPMT(ptr))
654 eDVBTableSpec table_spec;
655 ptr->getSpec(table_spec);
656 int pmt_version = table_spec.version & 0x1F; // just 5 bits
658 eServiceReferenceDVB ref;
659 pmthandler->getServiceReference(ref);
660 uint16_t program_number = ref.getServiceID().get();
661 std::map<uint16_t, uint8_t>::iterator it =
662 running_services.find(program_number);
664 if ( it != running_services.end() &&
665 (pmt_version == it->second) &&
666 !(caids.size() == 1 && caids[0] == 0xFFFF) )
668 eDebug("[eDVBCISlot] dont sent self capmt version twice");
672 std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
673 if ( i == ptr->getSections().end() )
677 unsigned char raw_data[2048];
679 // eDebug("send %s capmt for service %04x",
680 // it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
683 CaProgramMapSection capmt(*i++,
684 it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids );
685 while( i != ptr->getSections().end() )
690 capmt.writeToBuffer(raw_data);
692 // begin calc capmt length
695 if ( raw_data[3] & 0x80 )
698 int lenbytes = raw_data[3] & ~0x80;
700 wp = (wp << 8) | raw_data[4 + i++];
711 // end calc capmt length
712 // eDebug("ca_manager %p dump capmt:", ca_manager);
713 // for(int i=0;i<wp;i++)
714 // eDebugNoNewLine("%02x ", raw_data[i]);
717 if (caids.size() == 1 && caids[0] == 0xFFFF)
719 // eDebugNoNewLine("SEND EMPTY CAPMT.. old version is %02x", raw_data[hlen+3]);
720 raw_data[hlen+3] &= ~0x3E;
721 raw_data[hlen+3] |= ((pmt_version+1) & 0x1F) << 1;
722 // eDebug(" new version is %02x", raw_data[hlen+3]);
725 //dont need tag and lenfield
726 ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
727 running_services[program_number] = pmt_version;
733 void eDVBCISlot::removeService(uint16_t program_number)
735 if (program_number == 0xFFFF)
736 running_services.clear(); // remove all
738 running_services.erase(program_number); // remove single service
741 int eDVBCISlot::enableTS(int enable, int tuner)
743 // eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
744 // eDebug("eDVBCISlot::enableTS(%d %d)", enable, tuner);
746 FILE *input0, *input1, *ci;
747 if((input0 = fopen("/proc/stb/tsmux/input0", "wb")) == NULL) {
748 eDebug("cannot open /proc/stb/tsmux/input0");
751 if((input1 = fopen("/proc/stb/tsmux/input1", "wb")) == NULL) {
752 eDebug("cannot open /proc/stb/tsmux/input1");
755 if((ci = fopen("/proc/stb/tsmux/input2", "wb")) == NULL) {
756 eDebug("cannot open /proc/stb/tsmux/input2");
760 fprintf(ci, "%s", tuner==0 ? "A" : "B"); // configure CI data source (TunerA, TunerB)
761 fprintf(input0, "%s", tuner==0 && enable ? "CI" : "A"); // configure ATI input 0 data source
762 fprintf(input1, "%s", tuner==1 && enable ? "CI" : "B"); // configure ATI input 1 data source
770 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");