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 printf("FIXME: request for unknown slot\n");
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);
227 eDebug("str is %s", str.empty()?"empty" : str.c_str());
230 std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid);
231 if (appname.find("AlphaCrypt") != std::string::npos)
234 else if (str == "yes")
239 void eDVBCIInterfaces::recheckPMTHandlers()
241 // eDebug("recheckPMTHAndlers()");
242 for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
243 it != m_pmt_handlers.end(); ++it)
246 ePtr<eDVBService> service;
247 eServiceReferenceDVB ref;
248 eDVBServicePMTHandler *pmthandler = it->pmthandler;
249 eDVBServicePMTHandler::program p;
251 pmthandler->getServiceReference(ref);
252 pmthandler->getService(service);
253 if (!pmthandler->getProgramInfo(p))
256 for (std::set<uint16_t>::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
257 caids.push_front(*x);
259 service->m_ca = caids;
263 continue; // already running
266 caids = service->m_ca;
270 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
273 eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
276 const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
277 for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
279 std::vector<uint16_t>::const_iterator z =
280 std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
281 if ( z != ci_caids.end() && *z == *ca )
283 eDebug("found ci for caid %04x", *z);
292 bool send_ca_pmt = false;
293 if (ci_it->use_count) // check if this CI can descramble more than one service
295 PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
296 while (tmp != m_pmt_handlers.end())
300 eServiceReferenceDVB ref2;
301 tmp->pmthandler->getServiceReference(ref2);
302 eDVBChannelID s1, s2;
305 ref.getChannelID(s1);
306 ref2.getChannelID(s2);
308 if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(ci_it->getSlotID())))
310 it->cislot = tmp->cislot;
311 ++it->cislot->use_count;
313 // eDebug("usecount now %d", it->cislot->use_count);
324 // eDebug("usecount now %d", it->cislot->use_count);
325 enableTS(ci_it->getSlotID(), 1);
336 void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
338 // check if this pmthandler is already registered
339 PMTHandlerList::iterator it = m_pmt_handlers.begin();
340 while (it != m_pmt_handlers.end())
342 if ( *it++ == pmthandler )
346 eServiceReferenceDVB ref;
347 pmthandler->getServiceReference(ref);
348 eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
350 m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
351 recheckPMTHandlers();
354 void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
356 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
357 if (it != m_pmt_handlers.end())
359 eDVBCISlot *slot = it->cislot;
360 eDVBServicePMTHandler *pmthandler = it->pmthandler;
361 m_pmt_handlers.erase(it);
363 eServiceReferenceDVB service_to_remove;
364 pmthandler->getServiceReference(service_to_remove);
366 bool sameServiceExist=false;
367 for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
371 eServiceReferenceDVB ref;
372 i->pmthandler->getServiceReference(ref);
373 if ( ref == service_to_remove )
375 sameServiceExist=true;
381 if (slot && !sameServiceExist)
383 if (slot->getNumOfServices() > 1)
385 eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt",
386 service_to_remove.toString().c_str());
387 std::vector<uint16_t> caids;
388 caids.push_back(0xFFFF);
389 slot->sendCAPMT(pmthandler, caids); // send a capmt without caids to remove a running service
391 slot->removeService(service_to_remove.getServiceID().get());
394 if (slot && !--slot->use_count)
396 ASSERT(!slot->getNumOfServices());
397 enableTS(slot->getSlotID(),0);
400 // check if another service is waiting for the CI
401 recheckPMTHandlers();
404 void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
406 eDebug("[eDVBCIInterfaces] gotPMT");
407 PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
408 if (it != m_pmt_handlers.end() && it->cislot)
409 it->cislot->sendCAPMT(pmthandler);
412 int eDVBCIInterfaces::getMMIState(int slotid)
416 if( (slot = getSlot(slotid)) == 0 )
419 return slot->getMMIState();
422 int eDVBCISlot::send(const unsigned char *data, size_t len)
428 // printf("%02x ",data[i]);
431 if (sendqueue.empty())
432 res = ::write(fd, data, len);
434 if (res < 0 || (unsigned int)res != len)
436 unsigned char *d = new unsigned char[len];
437 memcpy(d, data, len);
438 sendqueue.push( queueData(d, len) );
439 notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
445 void eDVBCISlot::data(int what)
447 if(what == eSocketNotifier::Priority) {
448 if(state != stateRemoved) {
449 state = stateRemoved;
450 printf("ci removed\n");
451 while(sendqueue.size())
453 delete [] sendqueue.top().data;
456 eDVBCIInterfaces::getInstance()->ciRemoved(this);
457 eDVBCISession::deleteSessions(this);
458 notifier->setRequested(eSocketNotifier::Read);
459 eDVBCI_UI::getInstance()->setState(getSlotID(),0);
464 if (state == stateInvalid)
467 if(state != stateInserted) {
468 eDebug("ci inserted");
469 state = stateInserted;
470 eDVBCI_UI::getInstance()->setState(getSlotID(),1);
471 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
472 /* enable PRI to detect removal or errors */
475 if (what & eSocketNotifier::Read) {
478 r = ::read(fd, data, 4096);
483 // printf("%02x ",data[i]);
485 eDVBCISession::receiveData(this, data, r);
486 eDVBCISession::pollAll();
490 else if (what & eSocketNotifier::Write) {
491 if (!sendqueue.empty()) {
492 const queueData &qe = sendqueue.top();
493 int res = ::write(fd, qe.data, qe.len);
494 if (res >= 0 && (unsigned int)res == qe.len)
501 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
505 DEFINE_REF(eDVBCISlot);
507 eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
511 application_manager = 0;
518 sprintf(filename, "/dev/ci%d", nr);
520 fd = ::open(filename, O_RDWR | O_NONBLOCK);
522 eDebug("eDVBCISlot has fd %d", fd);
523 state = stateInvalid;
527 notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
528 CONNECT(notifier->activated, eDVBCISlot::data);
537 eDVBCISlot::~eDVBCISlot()
541 void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
543 application_manager=session;
546 void eDVBCISlot::setMMIManager( eDVBCIMMISession *session )
548 mmi_session = session;
551 void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session )
553 ca_manager = session;
556 int eDVBCISlot::getSlotID()
561 int eDVBCISlot::reset()
563 printf("edvbcislot: reset requested\n");
565 if (state == stateInvalid)
567 unsigned char buf[256];
569 while(::read(fd, buf, 256)>0);
570 state = stateResetted;
573 while(sendqueue.size())
575 delete [] sendqueue.top().data;
584 int eDVBCISlot::startMMI()
586 printf("edvbcislot: startMMI()\n");
588 if(application_manager)
589 application_manager->startMMI();
594 int eDVBCISlot::stopMMI()
596 printf("edvbcislot: stopMMI()\n");
599 mmi_session->stopMMI();
604 int eDVBCISlot::answerText(int answer)
606 printf("edvbcislot: answerText(%d)\n", answer);
609 mmi_session->answerText(answer);
614 int eDVBCISlot::getMMIState()
622 int eDVBCISlot::answerEnq(char *value)
624 printf("edvbcislot: answerENQ(%s)\n", value);
627 mmi_session->answerEnq(value);
632 int eDVBCISlot::cancelEnq()
634 printf("edvbcislot: cancelENQ\n");
637 mmi_session->cancelEnq();
642 int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
646 eDebug("no ca_manager (no CI plugged?)");
649 const std::vector<uint16_t> &caids = ids.empty() ? ca_manager->getCAIDs() : ids;
650 ePtr<eTable<ProgramMapSection> > ptr;
651 if (pmthandler->getPMT(ptr))
655 eDVBTableSpec table_spec;
656 ptr->getSpec(table_spec);
657 int pmt_version = table_spec.version & 0x1F; // just 5 bits
659 eServiceReferenceDVB ref;
660 pmthandler->getServiceReference(ref);
661 uint16_t program_number = ref.getServiceID().get();
662 std::map<uint16_t, uint8_t>::iterator it =
663 running_services.find(program_number);
665 if ( it != running_services.end() &&
666 (pmt_version == it->second) &&
667 !(caids.size() == 1 && caids[0] == 0xFFFF) )
669 eDebug("[eDVBCISlot] dont sent self capmt version twice");
673 std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
674 if ( i == ptr->getSections().end() )
678 unsigned char raw_data[2048];
680 // eDebug("send %s capmt for service %04x",
681 // it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
684 CaProgramMapSection capmt(*i++,
685 it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids );
686 while( i != ptr->getSections().end() )
691 capmt.writeToBuffer(raw_data);
693 // begin calc capmt length
696 if ( raw_data[3] & 0x80 )
699 int lenbytes = raw_data[3] & ~0x80;
701 wp = (wp << 8) | raw_data[4 + i++];
712 // end calc capmt length
713 // eDebug("ca_manager %p dump capmt:", ca_manager);
714 // for(int i=0;i<wp;i++)
715 // eDebugNoNewLine("%02x ", raw_data[i]);
718 if (caids.size() == 1 && caids[0] == 0xFFFF)
720 // eDebugNoNewLine("SEND EMPTY CAPMT.. old version is %02x", raw_data[hlen+3]);
721 raw_data[hlen+3] &= ~0x3E;
722 raw_data[hlen+3] |= ((pmt_version+1) & 0x1F) << 1;
723 // eDebug(" new version is %02x", raw_data[hlen+3]);
726 //dont need tag and lenfield
727 ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
728 running_services[program_number] = pmt_version;
734 void eDVBCISlot::removeService(uint16_t program_number)
736 if (program_number == 0xFFFF)
737 running_services.clear(); // remove all
739 running_services.erase(program_number); // remove single service
742 int eDVBCISlot::enableTS(int enable, int tuner)
744 // printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
745 // printf("eDVBCISlot::enableTS(%d %d)\n", enable, tuner);
747 FILE *input0, *input1, *ci;
748 if((input0 = fopen("/proc/stb/tsmux/input0", "wb")) == NULL) {
749 printf("cannot open /proc/stb/tsmux/input0\n");
752 if((input1 = fopen("/proc/stb/tsmux/input1", "wb")) == NULL) {
753 printf("cannot open /proc/stb/tsmux/input1\n");
756 if((ci = fopen("/proc/stb/tsmux/input2", "wb")) == NULL) {
757 printf("cannot open /proc/stb/tsmux/input2\n");
761 fprintf(ci, "%s", tuner==0 ? "A" : "B"); // configure CI data source (TunerA, TunerB)
762 fprintf(input0, "%s", tuner==0 && enable ? "CI" : "A"); // configure ATI input 0 data source
763 fprintf(input1, "%s", tuner==1 && enable ? "CI" : "B"); // configure ATI input 1 data source
771 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");