update (probably never used) libxine deccode plugin
[enigma2.git] / lib / dvb_ci / dvbci.cpp
1 #include <fcntl.h>
2 #include <sys/ioctl.h>
3
4 #include <lib/base/init.h>
5 #include <lib/base/init_num.h>
6 #include <lib/base/ebase.h>
7
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>
17
18 #include <dvbsi++/ca_program_map_section.h>
19
20 eDVBCIInterfaces *eDVBCIInterfaces::instance = 0;
21
22 eDVBCIInterfaces::eDVBCIInterfaces()
23 {
24         int num_ci = 0;
25         
26         instance = this;
27         
28         eDebug("scanning for common interfaces..");
29
30         while (1)
31         {
32                 struct stat s;
33                 char filename[128];
34                 sprintf(filename, "/dev/ci%d", num_ci);
35
36                 if (stat(filename, &s))
37                         break;
38
39                 ePtr<eDVBCISlot> cislot;
40
41                 cislot = new eDVBCISlot(eApp, num_ci);
42                 m_slots.push_back(cislot);
43
44                 ++num_ci;
45         }
46
47         eDebug("done, found %d common interface slots", num_ci);
48 }
49
50 eDVBCIInterfaces::~eDVBCIInterfaces()
51 {
52 }
53
54 eDVBCIInterfaces *eDVBCIInterfaces::getInstance()
55 {
56         return instance;
57 }
58
59 eDVBCISlot *eDVBCIInterfaces::getSlot(int slotid)
60 {
61         for(eSmartPtrList<eDVBCISlot>::iterator i(m_slots.begin()); i != m_slots.end(); ++i)
62                 if(i->getSlotID() == slotid)
63                         return i;
64
65         eDebug("FIXME: request for unknown slot");
66                         
67         return 0;
68 }
69
70 int eDVBCIInterfaces::getSlotState(int slotid)
71 {
72         eDVBCISlot *slot;
73
74         if( (slot = getSlot(slotid)) == 0 )
75                 return eDVBCISlot::stateInvalid;
76
77         return slot->getState();
78 }
79
80 int eDVBCIInterfaces::reset(int slotid)
81 {
82         eDVBCISlot *slot;
83
84         if( (slot = getSlot(slotid)) == 0 )
85                 return -1;
86
87         eDVBCISession::deleteSessions(slot);
88         ciRemoved(slot);
89
90         return slot->reset();
91 }
92
93 int eDVBCIInterfaces::initialize(int slotid)
94 {
95         eDVBCISlot *slot;
96
97         if( (slot = getSlot(slotid)) == 0 )
98                 return -1;
99
100         slot->removeService();
101
102         return sendCAPMT(slotid);
103 }
104
105 int eDVBCIInterfaces::sendCAPMT(int slotid)
106 {
107         eDVBCISlot *slot;
108
109         if( (slot = getSlot(slotid)) == 0 )
110                 return -1;
111
112         PMTHandlerList::iterator it = m_pmt_handlers.begin();
113         while (it != m_pmt_handlers.end())
114         {
115                 eDVBCISlot *tmp = it->cislot;
116                 while (tmp != slot)
117                         tmp = tmp->linked_next;
118                 if (tmp)
119                 {
120                         tmp->sendCAPMT(it->pmthandler);  // send capmt
121                         break;
122                 }
123                 ++it;
124         }
125
126         return 0;
127 }
128
129 int eDVBCIInterfaces::startMMI(int slotid)
130 {
131         eDVBCISlot *slot;
132
133         if( (slot = getSlot(slotid)) == 0 )
134                 return -1;
135         
136         return slot->startMMI();
137 }
138
139 int eDVBCIInterfaces::stopMMI(int slotid)
140 {
141         eDVBCISlot *slot;
142
143         if( (slot = getSlot(slotid)) == 0 )
144                 return -1;
145         
146         return slot->stopMMI();
147 }
148
149 int eDVBCIInterfaces::answerText(int slotid, int answer)
150 {
151         eDVBCISlot *slot;
152
153         if( (slot = getSlot(slotid)) == 0 )
154                 return -1;
155         
156         return slot->answerText(answer);
157 }
158
159 int eDVBCIInterfaces::answerEnq(int slotid, char *value)
160 {
161         eDVBCISlot *slot;
162
163         if( (slot = getSlot(slotid)) == 0 )
164                 return -1;
165         
166         return slot->answerEnq(value);
167 }
168
169 int eDVBCIInterfaces::cancelEnq(int slotid)
170 {
171         eDVBCISlot *slot;
172
173         if( (slot = getSlot(slotid)) == 0 )
174                 return -1;
175         
176         return slot->cancelEnq();
177 }
178
179 void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
180 {
181         for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
182                 it != m_pmt_handlers.end(); ++it)
183         {
184                 eServiceReferenceDVB ref;
185                 it->pmthandler->getServiceReference(ref);
186                 slot->removeService(ref.getServiceID().get());
187                 if (slot->use_count && !--slot->use_count)
188                 {
189                         if (slot->linked_next)
190                                 slot->linked_next->setSource(slot->current_source);
191                         else
192                                 setInputSource(slot->current_tuner, slot->current_source);
193
194                         if (it->cislot == slot) // remove the base slot
195                                 it->cislot = slot->linked_next;
196                         else
197                         {
198                                 if (slot->linked_next)
199                                 {
200                                         eDVBCISlot *tmp = it->cislot;
201                                         while(tmp->linked_next != slot)
202                                                 tmp = tmp->linked_next;
203                                         ASSERT(tmp);
204                                         tmp->linked_next = slot->linked_next;
205                                 }
206                         }
207                         slot->linked_next=0;
208                 }
209         }
210 }
211
212 static bool canDescrambleMultipleServices(int slotid)
213 {
214         char configStr[255];
215         snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid);
216         std::string str;
217         ePythonConfigQuery::getConfigValue(configStr, str);
218         if ( str == "auto" )
219         {
220                 std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid);
221                 if (appname.find("AlphaCrypt") != std::string::npos)
222                         return true;
223         }
224         else if (str == "yes")
225                 return true;
226         return false;
227 }
228
229 void eDVBCIInterfaces::recheckPMTHandlers()
230 {
231 //      eDebug("recheckPMTHAndlers()");
232         for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
233                 it != m_pmt_handlers.end(); ++it)
234         {
235                 CAID_LIST caids;
236                 ePtr<eDVBService> service;
237                 eServiceReferenceDVB ref;
238                 eDVBServicePMTHandler *pmthandler = it->pmthandler;
239                 eDVBServicePMTHandler::program p;
240
241                 pmthandler->getServiceReference(ref);
242                 pmthandler->getService(service);
243                 if (!pmthandler->getProgramInfo(p))
244                 {
245                         int cnt=0;
246                         for (std::set<uint16_t>::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
247                                 caids.push_front(*x);
248                         if (service && cnt)
249                                 service->m_ca = caids;
250                 }
251
252                 if (service)
253                         caids = service->m_ca;
254
255                 if (!caids.empty())
256                 {
257                         for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
258                         {
259                                 bool useThis=false;
260                                 eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
261                                 if (ca_manager)
262                                 {
263                                         const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
264                                         for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
265                                         {
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 )
269                                                 {
270 //                                                      eDebug("found ci for caid %04x", *z);
271                                                         useThis=true;
272                                                         break;
273                                                 }
274                                         }
275                                 }
276
277                                 if (useThis)
278                                 {
279                                         if (ci_it->use_count)  // check if this CI can descramble more than one service
280                                         {
281                                                 useThis = false;
282                                                 PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
283                                                 while (tmp != m_pmt_handlers.end())
284                                                 {
285                                                         if ( tmp->cislot == ci_it && it != tmp )
286                                                         {
287                                                                 eServiceReferenceDVB ref2;
288                                                                 tmp->pmthandler->getServiceReference(ref2);
289                                                                 eDVBChannelID s1, s2;
290                                                                 if (ref != ref2)
291                                                                 {
292                                                                         ref.getChannelID(s1);
293                                                                         ref2.getChannelID(s2);
294                                                                 }
295                                                                 if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(ci_it->getSlotID())))
296                                                                 {
297                                                                         useThis = true;
298                                                                         break;
299                                                                 }
300                                                         }
301                                                         ++tmp;
302                                                 }
303                                         }
304                                         if (useThis)
305                                         {
306                                                 // check if this CI is already assigned to this pmthandler
307                                                 eDVBCISlot *tmp = it->cislot;
308                                                 while(tmp)
309                                                 {
310                                                         if (tmp == ci_it)
311                                                                 break;
312                                                 }
313
314                                                 if (tmp) // ignore already assigned cislots...
315                                                         continue;
316
317                                                 ++ci_it->use_count;
318 //                                              eDebug("usecount now %d", ci_it->use_count);
319
320                                                 data_source ci_source=CI_A;
321                                                 switch(ci_it->getSlotID())
322                                                 {
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;
327                                                         default:
328                                                                 eDebug("try to get source for CI %d!!\n", ci_it->getSlotID());
329                                                                 break;
330                                                 }
331
332                                                 if (!it->cislot)
333                                                 {
334                                                         int tunernum = -1;
335                                                         eUsePtr<iDVBChannel> channel;
336                                                         if (!pmthandler->getChannel(channel))
337                                                         {
338                                                                 ePtr<iDVBFrontend> frontend;
339                                                                 if (!channel->getFrontend(frontend))
340                                                                 {
341                                                                         eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
342                                                                         tunernum = fe->getID();
343                                                                 }
344                                                         }
345                                                         ASSERT(tunernum != -1);
346                                                         data_source tuner_source = TUNER_A;
347                                                         switch (tunernum)
348                                                         {
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;
353                                                                 default:
354                                                                         eDebug("try to get source for tuner %d!!\n", tunernum);
355                                                                         break;
356                                                         }
357                                                         ci_it->current_tuner = tunernum;
358                                                         setInputSource(tunernum, ci_source);
359                                                         ci_it->setSource(tuner_source);
360                                                 }
361                                                 else
362                                                 {
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);
367                                                 }
368                                                 it->cislot = ci_it;
369                                                 gotPMT(pmthandler);
370                                         }
371                                 }
372                         }
373                 }
374         }
375 }
376
377 void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
378 {
379         // check if this pmthandler is already registered
380         PMTHandlerList::iterator it = m_pmt_handlers.begin();
381         while (it != m_pmt_handlers.end())
382         {
383                 if ( *it++ == pmthandler )
384                         return;
385         }
386
387         eServiceReferenceDVB ref;
388         pmthandler->getServiceReference(ref);
389         eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
390
391         m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
392         recheckPMTHandlers();
393 }
394
395 void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
396 {
397         PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
398         if (it != m_pmt_handlers.end())
399         {
400                 eDVBCISlot *slot = it->cislot;
401                 eDVBServicePMTHandler *pmthandler = it->pmthandler;
402                 m_pmt_handlers.erase(it);
403
404                 eServiceReferenceDVB service_to_remove;
405                 pmthandler->getServiceReference(service_to_remove);
406
407                 bool sameServiceExist=false;
408                 for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
409                 {
410                         if (i->cislot)
411                         {
412                                 eServiceReferenceDVB ref;
413                                 i->pmthandler->getServiceReference(ref);
414                                 if ( ref == service_to_remove )
415                                 {
416                                         sameServiceExist=true;
417                                         break;
418                                 }
419                         }
420                 }
421
422                 while(slot)
423                 {
424                         if (!sameServiceExist)
425                         {
426                                 if (slot->getNumOfServices() > 1)
427                                 {
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
433                                 }
434                                 slot->removeService(service_to_remove.getServiceID().get());
435                         }
436
437                         eDVBCISlot *next = slot->linked_next;
438                         if (!--slot->use_count)
439                         {
440                                 if (slot->linked_next)
441                                         slot->linked_next->setSource(slot->current_source);
442                                 else
443                                         setInputSource(slot->current_tuner, slot->current_source);
444
445                                 if (it->cislot == slot) // remove the base slot
446                                         it->cislot = slot->linked_next;
447                                 else
448                                 {
449                                         if (slot->linked_next)
450                                         {
451                                                 eDVBCISlot *tmp = it->cislot;
452                                                 while(tmp->linked_next != slot)
453                                                         tmp = tmp->linked_next;
454                                                 ASSERT(tmp);
455                                                 tmp->linked_next = slot->linked_next;
456                                         }
457                                 }
458                                 slot->linked_next=0;
459                         }
460 //                      eDebug("use_count is now %d", slot->use_count);
461                         slot = next;
462                 }
463         }
464         // check if another service is waiting for the CI
465         recheckPMTHandlers();
466 }
467
468 void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
469 {
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)
473         {
474                 eDVBCISlot *tmp = it->cislot;
475                 while(tmp)
476                 {
477                         tmp->sendCAPMT(pmthandler);
478                         tmp = tmp->linked_next;
479                 }
480         }
481 }
482
483 int eDVBCIInterfaces::getMMIState(int slotid)
484 {
485         eDVBCISlot *slot;
486
487         if( (slot = getSlot(slotid)) == 0 )
488                 return -1;
489         
490         return slot->getMMIState();
491 }
492
493 int eDVBCIInterfaces::setInputSource(int tuner_no, data_source source)
494 {
495 //      eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
496 //      eDebug("eDVBCIInterfaces::setInputSource(%d %d)", tuner_no, (int)source);
497 #if defined(DM8000)
498         char buf[64];
499         snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
500
501         FILE *input=0;
502         if((input = fopen(buf, "wb")) == NULL) {
503                 eDebug("cannot open %s", buf);
504                 return 0;
505         }
506
507         if (input > 3)
508                 eDebug("setInputSource(%d, %d) failed... dm8000 just have four inputs", tuner_no, (int)source);
509
510         switch(source)
511         {
512                 case CI_A:
513                         fprintf(input, "CI0");
514                         break;
515                 case CI_B:
516                         fprintf(input, "CI1");
517                         break;
518                 case CI_C:
519                         fprintf(input, "CI2");
520                         break;
521                 case CI_D:
522                         fprintf(input, "CI3");
523                         break;
524                 case TUNER_A:
525                         fprintf(input, "A");
526                         break;
527                 case TUNER_B:
528                         fprintf(input, "B");
529                         break;
530                 case TUNER_C:
531                         fprintf(input, "C");
532                         break;
533                 case TUNER_D:
534                         fprintf(input, "D");
535                         break;
536                 default:
537                         eDebug("setInputSource for input %d failed!!!\n", (int)source);
538                         break;
539         }
540
541         fclose(input);
542 #else // force DM7025
543         char buf[64];
544         snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
545
546         if (tuner_no > 1)
547                 eDebug("setInputSource(%d, %d) failed... dm7025 just have two inputs", tuner_no, (int)source);
548
549         FILE *input=0;
550         if((input = fopen(buf, "wb")) == NULL) {
551                 eDebug("cannot open %s", buf);
552                 return 0;
553         }
554
555         switch(source)
556         {
557                 case CI_A:
558                         fprintf(input, "CI");
559                         break;
560                 case TUNER_A:
561                         fprintf(input, "A");
562                         break;
563                 case TUNER_B:
564                         fprintf(input, "B");
565                         break;
566                 default:
567                         eDebug("setInputSource for input %d failed!!!\n", (int)source);
568                         break;
569         }
570
571         fclose(input);
572 #endif
573         eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source);
574         return 0;
575 }
576
577
578 int eDVBCISlot::send(const unsigned char *data, size_t len)
579 {
580         int res=0;
581         //int i;
582         //eDebugNoNewLine("< ");
583         //for(i=0;i<len;i++)
584         //      eDebugNoNewLine("%02x ",data[i]);
585         //eDebug("");
586
587         if (sendqueue.empty())
588                 res = ::write(fd, data, len);
589
590         if (res < 0 || (unsigned int)res != len)
591         {
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);
596         }
597
598         return res;
599 }
600
601 void eDVBCISlot::data(int what)
602 {
603         if(what == eSocketNotifier::Priority) {
604                 if(state != stateRemoved) {
605                         state = stateRemoved;
606                         eDebug("ci removed");
607                         while(sendqueue.size())
608                         {
609                                 delete [] sendqueue.top().data;
610                                 sendqueue.pop();
611                         }
612                         eDVBCIInterfaces::getInstance()->ciRemoved(this);
613                         eDVBCISession::deleteSessions(this);
614                         notifier->setRequested(eSocketNotifier::Read);
615                         eDVBCI_UI::getInstance()->setState(getSlotID(),0);
616                 }
617                 return;
618         }
619
620         if (state == stateInvalid)
621                 reset();
622
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 */
629         }
630
631         if (what & eSocketNotifier::Read) {
632                 __u8 data[4096];
633                 int r;
634                 r = ::read(fd, data, 4096);
635                 if(r > 0) {
636 //                      int i;
637 //                      eDebugNoNewLine("> ");
638 //                      for(i=0;i<r;i++)
639 //                              eDebugNoNewLine("%02x ",data[i]);
640 //                      eDebug("");
641                         eDVBCISession::receiveData(this, data, r);
642                         eDVBCISession::pollAll();
643                         return;
644                 }
645         }
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)
651                         {
652                                 delete [] qe.data;
653                                 sendqueue.pop();
654                         }
655                 }
656                 else
657                         notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
658         }
659 }
660
661 DEFINE_REF(eDVBCISlot);
662
663 eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
664 {
665         char filename[128];
666
667         application_manager = 0;
668         mmi_session = 0;
669         ca_manager = 0;
670         use_count = 0;
671         linked_next = 0;
672         
673         slotid = nr;
674
675         sprintf(filename, "/dev/ci%d", nr);
676
677         fd = ::open(filename, O_RDWR | O_NONBLOCK);
678
679         eDebug("eDVBCISlot has fd %d", fd);
680         state = stateInvalid;
681
682         if (fd >= 0)
683         {
684                 notifier = new eSocketNotifier(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
685                 CONNECT(notifier->activated, eDVBCISlot::data);
686         } else
687         {
688                 perror(filename);
689         }
690 }
691
692 eDVBCISlot::~eDVBCISlot()
693 {
694 }
695
696 void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
697 {
698         application_manager=session;
699 }
700
701 void eDVBCISlot::setMMIManager( eDVBCIMMISession *session )
702 {
703         mmi_session = session;
704 }
705
706 void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session )
707 {
708         ca_manager = session;
709 }
710
711 int eDVBCISlot::getSlotID()
712 {
713         return slotid;
714 }
715
716 int eDVBCISlot::reset()
717 {
718         eDebug("edvbcislot: reset requested");
719
720         if (state == stateInvalid)
721         {
722                 unsigned char buf[256];
723                 eDebug("ci flush");
724                 while(::read(fd, buf, 256)>0);
725                 state = stateResetted;
726         }
727
728         while(sendqueue.size())
729         {
730                 delete [] sendqueue.top().data;
731                 sendqueue.pop();
732         }
733
734         ioctl(fd, 0);
735
736         return 0;
737 }
738
739 int eDVBCISlot::startMMI()
740 {
741         eDebug("edvbcislot: startMMI()");
742         
743         if(application_manager)
744                 application_manager->startMMI();
745         
746         return 0;
747 }
748
749 int eDVBCISlot::stopMMI()
750 {
751         eDebug("edvbcislot: stopMMI()");
752
753         if(mmi_session)
754                 mmi_session->stopMMI();
755         
756         return 0;
757 }
758
759 int eDVBCISlot::answerText(int answer)
760 {
761         eDebug("edvbcislot: answerText(%d)", answer);
762
763         if(mmi_session)
764                 mmi_session->answerText(answer);
765
766         return 0;
767 }
768
769 int eDVBCISlot::getMMIState()
770 {
771         if(mmi_session)
772                 return 1;
773
774         return 0;
775 }
776
777 int eDVBCISlot::answerEnq(char *value)
778 {
779         eDebug("edvbcislot: answerENQ(%s)", value);
780
781         if(mmi_session)
782                 mmi_session->answerEnq(value);
783
784         return 0;
785 }
786
787 int eDVBCISlot::cancelEnq()
788 {
789         eDebug("edvbcislot: cancelENQ");
790
791         if(mmi_session)
792                 mmi_session->cancelEnq();
793
794         return 0;
795 }
796
797 int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
798 {
799         if (!ca_manager)
800         {
801                 eDebug("no ca_manager (no CI plugged?)");
802                 return -1;
803         }
804         const std::vector<uint16_t> &caids = ids.empty() ? ca_manager->getCAIDs() : ids;
805         ePtr<eTable<ProgramMapSection> > ptr;
806         if (pmthandler->getPMT(ptr))
807                 return -1;
808         else
809         {
810                 eDVBTableSpec table_spec;
811                 ptr->getSpec(table_spec);
812                 int pmt_version = table_spec.version & 0x1F; // just 5 bits
813
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);
819
820                 if ( it != running_services.end() &&
821                         (pmt_version == it->second) &&
822                         !(caids.size() == 1 && caids[0] == 0xFFFF) )
823                 {
824                         eDebug("[eDVBCISlot] dont send self capmt version twice");
825                         return -1;
826                 }
827
828                 std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
829                 if ( i == ptr->getSections().end() )
830                         return -1;
831                 else
832                 {
833                         unsigned char raw_data[2048];
834
835 //                      eDebug("send %s capmt for service %04x",
836 //                              it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
837 //                              program_number);
838
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() )
842                         {
843                 //                      eDebug("append");
844                                 capmt.append(*i++);
845                         }
846                         capmt.writeToBuffer(raw_data);
847 #if 1
848 // begin calc capmt length
849                         int wp=0;
850                         int hlen;
851                         if ( raw_data[3] & 0x80 )
852                         {
853                                 int i=0;
854                                 int lenbytes = raw_data[3] & ~0x80;
855                                 while(i < lenbytes)
856                                         wp = (wp << 8) | raw_data[4 + i++];
857                                 wp+=4;
858                                 wp+=lenbytes;
859                                 hlen = 4 + lenbytes;
860                         }
861                         else
862                         {
863                                 wp = raw_data[3];
864                                 wp+=4;
865                                 hlen = 4;
866                         }
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]);
871 //                      eDebug("");
872 #endif
873                         if (caids.size() == 1 && caids[0] == 0xFFFF)
874                         {
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]);
879                         }
880
881                         //dont need tag and lenfield
882                         ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
883                         running_services[program_number] = pmt_version;
884                 }
885         }
886         return 0;
887 }
888
889 void eDVBCISlot::removeService(uint16_t program_number)
890 {
891         if (program_number == 0xFFFF)
892                 running_services.clear();  // remove all
893         else
894                 running_services.erase(program_number);  // remove single service
895 }
896
897 int eDVBCISlot::setSource(data_source source)
898 {
899         current_source = source;
900 #if defined(DM8000)
901         char buf[64];
902         snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slotid);
903         FILE *ci = fopen(buf, "wb");
904         switch(source)
905         {
906                 case CI_A:
907                         fprintf(ci, "CI0");
908                         break;
909                 case CI_B:
910                         fprintf(ci, "CI1");
911                         break;
912                 case CI_C:
913                         fprintf(ci, "CI2");
914                         break;
915                 case CI_D:
916                         fprintf(ci, "CI3");
917                         break;
918                 case TUNER_A:
919                         fprintf(ci, "A");
920                         break;
921                 case TUNER_B:
922                         fprintf(ci, "B");
923                         break;
924                 case TUNER_C:
925                         fprintf(ci, "C");
926                         break;
927                 case TUNER_D:
928                         fprintf(ci, "D");
929                         break;
930                 default:
931                         eDebug("setSource %d failed!!!\n", (int)source);
932                         break;
933         }
934         fclose(ci);
935 #else // force DM7025
936 //      eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
937 //      eDebug("eDVBCISlot::enableTS(%d %d)", enable, (int)source);
938         FILE *ci = fopen("/proc/stb/tsmux/input2", "wb");
939         if(ci == NULL) {
940                 eDebug("cannot open /proc/stb/tsmux/input2");
941                 return 0;
942         }
943         if (source != TUNER_A && source != TUNER_B)
944                 eDebug("setSource %d failed!!!\n", (int)source);
945         else
946                 fprintf(ci, "%s", source==TUNER_A ? "A" : "B");  // configure CI data source (TunerA, TunerB)
947         fclose(ci);
948 #endif
949         eDebug("eDVBCISlot->setSource(%d)", (int)source);
950         return 0;
951 }
952
953 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");