+ return slot->stopMMI();
+}
+
+int eDVBCIInterfaces::answerText(int slotid, int answer)
+{
+ eDVBCISlot *slot;
+
+ if( (slot = getSlot(slotid)) == 0 )
+ return -1;
+
+ return slot->answerText(answer);
+}
+
+int eDVBCIInterfaces::answerEnq(int slotid, char *value)
+{
+ eDVBCISlot *slot;
+
+ if( (slot = getSlot(slotid)) == 0 )
+ return -1;
+
+ return slot->answerEnq(value);
+}
+
+int eDVBCIInterfaces::cancelEnq(int slotid)
+{
+ eDVBCISlot *slot;
+
+ if( (slot = getSlot(slotid)) == 0 )
+ return -1;
+
+ return slot->cancelEnq();
+}
+
+void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
+{
+ for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
+ it != m_pmt_handlers.end(); ++it)
+ {
+ if (it->cislot == slot)
+ {
+ eServiceReferenceDVB ref;
+ it->pmthandler->getServiceReference(ref);
+ slot->removeService(ref.getServiceID().get());
+ if (!--slot->use_count)
+ enableTS(slot->getSlotID(), 0);
+ it->cislot=0;
+ }
+ }
+}
+
+void eDVBCIInterfaces::recheckPMTHandlers()
+{
+// eDebug("recheckPMTHAndlers()");
+ for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
+ it != m_pmt_handlers.end(); ++it)
+ {
+ CAID_LIST caids;
+ ePtr<eDVBService> service;
+ eServiceReferenceDVB ref;
+ eDVBServicePMTHandler *pmthandler = it->pmthandler;
+ eDVBServicePMTHandler::program p;
+
+ pmthandler->getServiceReference(ref);
+ pmthandler->getService(service);
+ if (!pmthandler->getProgramInfo(p))
+ {
+ int cnt=0;
+ for (std::set<uint16_t>::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
+ caids.push_front(*x);
+ if (service && cnt)
+ service->m_ca = caids;
+ }
+
+ if (it->cislot)
+ continue; // already running
+
+ if (service)
+ caids = service->m_ca;
+
+ if (!caids.empty())
+ {
+ for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
+ {
+ if (ci_it->getState() == eDVBCISlot::stateInvalid)
+ ci_it->reset();
+
+ bool useThis=false;
+ eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
+ if (ca_manager)
+ {
+ const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
+ for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
+ {
+ std::vector<uint16_t>::const_iterator z =
+ std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
+ if ( z != ci_caids.end() && *z == *ca )
+ {
+ eDebug("found ci for caid %04x", *z);
+ useThis=true;
+ break;
+ }
+ }
+ }
+
+ if (useThis)
+ {
+ bool send_ca_pmt = false;
+ if (ci_it->use_count) // check if this CI can descramble more than one service
+ {
+ PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
+ while (tmp != m_pmt_handlers.end())
+ {
+ if ( tmp->cislot )
+ {
+ bool canHandleMultipleServices=false;
+ eServiceReferenceDVB ref2;
+ tmp->pmthandler->getServiceReference(ref2);
+ eDVBChannelID s1, s2;
+ if (ref != ref2)
+ {
+ ref.getChannelID(s1);
+ ref2.getChannelID(s2);
+ // FIXME .. build a "ci can handle multiple services" config entry
+ // Yes / No / Auto
+ if ( eDVBCI_UI::getInstance()->getAppName(ci_it->getSlotID()) == "AlphaCrypt" )
+ {
+ canHandleMultipleServices = true;
+ eDebug("Alphacrypt can handle multiple services");
+ }
+ }
+ if (ref == ref2 || (s1 == s2 && canHandleMultipleServices) )
+ {
+ it->cislot = tmp->cislot;
+ ++it->cislot->use_count;
+ send_ca_pmt = true;
+// eDebug("usecount now %d", it->cislot->use_count);
+ break;
+ }
+ }
+ ++tmp;
+ }
+ }
+ else
+ {
+ ci_it->use_count=1;
+ it->cislot = ci_it;
+// eDebug("usecount now %d", it->cislot->use_count);
+ enableTS(ci_it->getSlotID(), 1);
+ send_ca_pmt = true;
+ }
+ if (send_ca_pmt)
+ gotPMT(pmthandler);
+ }
+ }
+ }
+ }
+}
+
+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;
+ }
+
+ 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)
+{
+ PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
+ if (it != m_pmt_handlers.end())
+ {
+ eDVBCISlot *slot = it->cislot;
+ eDVBServicePMTHandler *pmthandler = it->pmthandler;
+ m_pmt_handlers.erase(it);
+
+ 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)
+ {
+ eServiceReferenceDVB ref;
+ i->pmthandler->getServiceReference(ref);
+ if ( ref == service_to_remove )
+ {
+ sameServiceExist=true;
+ break;
+ }
+ }
+
+ if (slot && !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<uint16_t> 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());
+ }
+
+ if (slot && !--slot->use_count)
+ {
+ ASSERT(!slot->getNumOfServices());
+ enableTS(slot->getSlotID(),0);
+ }
+ }
+ // 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);
+ if (it != m_pmt_handlers.end() && it->cislot)
+ it->cislot->sendCAPMT(pmthandler);
+}
+
+int eDVBCIInterfaces::getMMIState(int slotid)
+{
+ eDVBCISlot *slot;
+
+ if( (slot = getSlot(slotid)) == 0 )
+ return -1;
+
+ return slot->getMMIState();
+}
+
+int eDVBCISlot::send(const unsigned char *data, size_t len)
+{
+ int res=0;
+ //int i;
+ //printf("< ");
+ //for(i=0;i<len;i++)
+ // printf("%02x ",data[i]);
+ //printf("\n");
+
+ if (sendqueue.empty())
+ res = ::write(fd, data, len);
+
+ 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;
+}
+
+void eDVBCISlot::data(int what)
+{
+ if(what == eSocketNotifier::Priority) {
+ if(state != stateRemoved) {
+ state = stateRemoved;
+ printf("ci removed\n");
+ while(sendqueue.size())
+ {
+ delete [] sendqueue.top().data;
+ sendqueue.pop();
+ }
+ eDVBCIInterfaces::getInstance()->ciRemoved(this);
+ eDVBCISession::deleteSessions(this);
+ notifier->setRequested(eSocketNotifier::Read);
+ eDVBCI_UI::getInstance()->setState(getSlotID(),0);
+ }
+ return;
+ }
+
+ if (state == stateInvalid)
+ return;
+
+ if(state != stateInserted) {
+ eDebug("ci inserted");
+ state = stateInserted;
+ eDVBCI_UI::getInstance()->setState(getSlotID(),1);
+ notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
+ /* enable PRI to detect removal or errors */
+ }
+
+ if (what & eSocketNotifier::Read) {
+ __u8 data[4096];
+ int r;
+ r = ::read(fd, data, 4096);
+ if(r > 0) {
+// int i;
+// printf("> ");
+// for(i=0;i<r;i++)
+// printf("%02x ",data[i]);
+// printf("\n");
+ eDVBCISession::receiveData(this, data, r);
+ eDVBCISession::pollAll();
+ return;
+ }
+ }
+ 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);
+ }