a0166355b7c8391307ef5a04ba580e51ebe7d366
[vuplus_dvbapp] / 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/db.h>
11 #include <lib/dvb/pmt.h>
12 #include <lib/dvb_ci/dvbci.h>
13 #include <lib/dvb_ci/dvbci_session.h>
14 #include <lib/dvb_ci/dvbci_camgr.h>
15 #include <lib/dvb_ci/dvbci_ui.h>
16 #include <lib/dvb_ci/dvbci_appmgr.h>
17 #include <lib/dvb_ci/dvbci_mmi.h>
18
19 #include <dvbsi++/ca_program_map_section.h>
20
21 //#define CIDEBUG 1
22
23 #ifdef CIDEBUG
24         #define eDebugCI(x...) eDebug(x)
25 #else
26         #define eDebugCI(x...)
27 #endif
28
29 eDVBCIInterfaces *eDVBCIInterfaces::instance = 0;
30
31 eDVBCIInterfaces::eDVBCIInterfaces()
32 {
33         int num_ci = 0;
34         
35         instance = this;
36         
37         eDebug("scanning for common interfaces..");
38
39         while (1)
40         {
41                 struct stat s;
42                 char filename[128];
43                 sprintf(filename, "/dev/ci%d", num_ci);
44
45                 if (stat(filename, &s))
46                         break;
47
48                 ePtr<eDVBCISlot> cislot;
49
50                 cislot = new eDVBCISlot(eApp, num_ci);
51                 m_slots.push_back(cislot);
52
53                 ++num_ci;
54         }
55
56         for (eSmartPtrList<eDVBCISlot>::iterator it(m_slots.begin()); it != m_slots.end(); ++it)
57                 it->setSource(TUNER_A);
58
59         if (num_ci > 1) // // FIXME .. we force DM8000 when more than one CI Slot is avail
60         {
61                 setInputSource(0, TUNER_A);
62                 setInputSource(1, TUNER_B);
63                 setInputSource(2, TUNER_C);
64                 setInputSource(3, TUNER_D);
65         }
66         else
67         {
68                 setInputSource(0, TUNER_A);
69                 setInputSource(1, TUNER_B);
70         }
71
72         eDebug("done, found %d common interface slots", num_ci);
73 }
74
75 eDVBCIInterfaces::~eDVBCIInterfaces()
76 {
77 }
78
79 eDVBCIInterfaces *eDVBCIInterfaces::getInstance()
80 {
81         return instance;
82 }
83
84 eDVBCISlot *eDVBCIInterfaces::getSlot(int slotid)
85 {
86         for(eSmartPtrList<eDVBCISlot>::iterator i(m_slots.begin()); i != m_slots.end(); ++i)
87                 if(i->getSlotID() == slotid)
88                         return i;
89
90         eDebug("FIXME: request for unknown slot");
91                         
92         return 0;
93 }
94
95 int eDVBCIInterfaces::getSlotState(int slotid)
96 {
97         eDVBCISlot *slot;
98
99         if( (slot = getSlot(slotid)) == 0 )
100                 return eDVBCISlot::stateInvalid;
101
102         return slot->getState();
103 }
104
105 int eDVBCIInterfaces::reset(int slotid)
106 {
107         eDVBCISlot *slot;
108
109         if( (slot = getSlot(slotid)) == 0 )
110                 return -1;
111
112         return slot->reset();
113 }
114
115 int eDVBCIInterfaces::initialize(int slotid)
116 {
117         eDVBCISlot *slot;
118
119         if( (slot = getSlot(slotid)) == 0 )
120                 return -1;
121
122         slot->removeService();
123
124         return sendCAPMT(slotid);
125 }
126
127 int eDVBCIInterfaces::sendCAPMT(int slotid)
128 {
129         eDVBCISlot *slot;
130
131         if( (slot = getSlot(slotid)) == 0 )
132                 return -1;
133
134         PMTHandlerList::iterator it = m_pmt_handlers.begin();
135         while (it != m_pmt_handlers.end())
136         {
137                 eDVBCISlot *tmp = it->cislot;
138                 while (tmp && tmp != slot)
139                         tmp = tmp->linked_next;
140                 if (tmp)
141                 {
142                         tmp->sendCAPMT(it->pmthandler);  // send capmt
143                         break;
144                 }
145                 ++it;
146         }
147
148         return 0;
149 }
150
151 int eDVBCIInterfaces::startMMI(int slotid)
152 {
153         eDVBCISlot *slot;
154
155         if( (slot = getSlot(slotid)) == 0 )
156                 return -1;
157         
158         return slot->startMMI();
159 }
160
161 int eDVBCIInterfaces::stopMMI(int slotid)
162 {
163         eDVBCISlot *slot;
164
165         if( (slot = getSlot(slotid)) == 0 )
166                 return -1;
167         
168         return slot->stopMMI();
169 }
170
171 int eDVBCIInterfaces::answerText(int slotid, int answer)
172 {
173         eDVBCISlot *slot;
174
175         if( (slot = getSlot(slotid)) == 0 )
176                 return -1;
177         
178         return slot->answerText(answer);
179 }
180
181 int eDVBCIInterfaces::answerEnq(int slotid, char *value)
182 {
183         eDVBCISlot *slot;
184
185         if( (slot = getSlot(slotid)) == 0 )
186                 return -1;
187         
188         return slot->answerEnq(value);
189 }
190
191 int eDVBCIInterfaces::cancelEnq(int slotid)
192 {
193         eDVBCISlot *slot;
194
195         if( (slot = getSlot(slotid)) == 0 )
196                 return -1;
197         
198         return slot->cancelEnq();
199 }
200
201 void eDVBCIInterfaces::ciRemoved(eDVBCISlot *slot)
202 {
203         eDebug("CI Slot %d: removed... usecount %d", slot->getSlotID(), slot->use_count);
204         for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
205                 it != m_pmt_handlers.end(); ++it)
206         {
207                 eServiceReferenceDVB ref;
208                 it->pmthandler->getServiceReference(ref);
209                 eDebugCI("check %s cislot %p %d\n", ref.toString().c_str(), it->cislot, it->cislot?it->cislot->getSlotID() : -1);
210                 slot->removeService(ref.getServiceID().get());
211                 if (slot->use_count && !--slot->use_count)
212                 {
213                         if (slot->linked_next)
214                                 slot->linked_next->setSource(slot->current_source);
215                         else // last CI in chain
216                                 setInputSource(slot->current_tuner, slot->current_source);
217
218                         if (it->cislot == slot) // remove the base slot
219                         {
220                                 it->cislot = slot->linked_next;
221                                 eDebugCI("base removed.. so slot is now %p", it->cislot);
222                         }
223                         else
224                         {
225                                 eDebugCI("not base removed.. %d", it->cislot->getSlotID());
226                                 eDVBCISlot *tmp = it->cislot;
227                                 while(tmp->linked_next != slot)
228                                         tmp = tmp->linked_next;
229                                 ASSERT(tmp);
230                                 if (slot->linked_next)
231                                         tmp->linked_next = slot->linked_next;
232                                 else
233                                         tmp->linked_next = 0;
234                         }
235                         slot->linked_next=0;
236                         slot->user_mapped=false;
237                 }
238         }
239         recheckPMTHandlers();
240 }
241
242 static bool canDescrambleMultipleServices(int slotid)
243 {
244         char configStr[255];
245         snprintf(configStr, 255, "config.ci.%d.canDescrambleMultipleServices", slotid);
246         std::string str;
247         ePythonConfigQuery::getConfigValue(configStr, str);
248         if ( str == "auto" )
249         {
250                 std::string appname = eDVBCI_UI::getInstance()->getAppName(slotid);
251                 if (appname.find("AlphaCrypt") != std::string::npos)
252                         return true;
253         }
254         else if (str == "yes")
255                 return true;
256         return false;
257 }
258
259 void eDVBCIInterfaces::recheckPMTHandlers()
260 {
261         eDebugCI("recheckPMTHAndlers()");
262         for (PMTHandlerList::iterator it(m_pmt_handlers.begin());
263                 it != m_pmt_handlers.end(); ++it)
264         {
265                 CAID_LIST caids;
266                 ePtr<eDVBService> service;
267                 eServiceReferenceDVB ref;
268                 eDVBCISlot *tmp = it->cislot;
269                 eDVBServicePMTHandler *pmthandler = it->pmthandler;
270                 eDVBServicePMTHandler::program p;
271                 bool first_plugged_cis_exist = false;
272
273                 pmthandler->getServiceReference(ref);
274                 pmthandler->getService(service);
275
276                 eDebugCI("recheck %p %s", pmthandler, ref.toString().c_str());
277                 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
278                         if (ci_it->first_plugged && ci_it->getCAManager())
279                         {
280                                 eDebug("Slot %d first plugged", ci_it->getSlotID());
281                                 ci_it->first_plugged = false;
282                                 first_plugged_cis_exist = true;
283                         }
284
285                 // check if this pmt handler has already assigned CI(s) .. and this CI(s) are already running
286                 if (!first_plugged_cis_exist)
287                 {
288                         while(tmp)
289                         {
290                                 if (!tmp->running_services.empty())
291                                         break;
292                                 tmp=tmp->linked_next;
293                         }
294                         if (tmp) // we dont like to change tsmux for running services
295                         {
296                                 eDebugCI("already assigned and running CI!\n");
297                                 continue;
298                         }
299                 }
300
301                 if (!pmthandler->getProgramInfo(p))
302                 {
303                         int cnt=0;
304                         for (caidSet::reverse_iterator x(p.caids.rbegin()); x != p.caids.rend(); ++x, ++cnt)
305                                 caids.push_front(*x);
306                         if (service && cnt)
307                                 service->m_ca = caids;
308                 }
309
310                 if (service)
311                         caids = service->m_ca;
312
313                 if (caids.empty())
314                         continue; // unscrambled service
315
316                 for (eSmartPtrList<eDVBCISlot>::iterator ci_it(m_slots.begin()); ci_it != m_slots.end(); ++ci_it)
317                 {
318                         eDebugCI("check Slot %d", ci_it->getSlotID());
319                         bool useThis=false;
320                         bool user_mapped=true;
321                         eDVBCICAManagerSession *ca_manager = ci_it->getCAManager();
322
323                         if (ca_manager)
324                         {
325                                 int mask=0;
326                                 if (!ci_it->possible_services.empty())
327                                 {
328                                         mask |= 1;
329                                         serviceSet::iterator it = ci_it->possible_services.find(ref);
330                                         if (it != ci_it->possible_services.end())
331                                         {
332                                                 eDebug("'%s' is in service list of slot %d... so use it", ref.toString().c_str(), ci_it->getSlotID());
333                                                 useThis = true;
334                                         }
335                                         else // check parent
336                                         {
337                                                 eServiceReferenceDVB parent_ref = ref.getParentServiceReference();
338                                                 if (parent_ref)
339                                                 {
340                                                         it = ci_it->possible_services.find(ref);
341                                                         if (it != ci_it->possible_services.end())
342                                                         {
343                                                                 eDebug("parent '%s' of '%s' is in service list of slot %d... so use it",
344                                                                         parent_ref.toString().c_str(), ref.toString().c_str(), ci_it->getSlotID());
345                                                                 useThis = true;
346                                                         }
347                                                 }
348                                         }
349                                 }
350                                 if (!useThis && !ci_it->possible_providers.empty())
351                                 {
352                                         eDVBNamespace ns = ref.getDVBNamespace();
353                                         mask |= 2;
354                                         if (!service) // subservice?
355                                         {
356                                                 eServiceReferenceDVB parent_ref = ref.getParentServiceReference();
357                                                 eDVBDB::getInstance()->getService(parent_ref, service);
358                                         }
359                                         if (service)
360                                         {
361                                                 providerSet::iterator it = ci_it->possible_providers.find(providerPair(service->m_provider_name, ns.get()));
362                                                 if (it != ci_it->possible_providers.end())
363                                                 {
364                                                         eDebug("'%s/%08x' is in provider list of slot %d... so use it", service->m_provider_name.c_str(), ns.get(), ci_it->getSlotID());
365                                                         useThis = true;
366                                                 }
367                                         }
368                                 }
369                                 if (!useThis && !ci_it->possible_caids.empty())
370                                 {
371                                         mask |= 4;
372                                         for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
373                                         {
374                                                 caidSet::iterator it = ci_it->possible_caids.find(*ca);
375                                                 if (it != ci_it->possible_caids.end())
376                                                 {
377                                                         eDebug("caid '%04x' is in caid list of slot %d... so use it", *ca, ci_it->getSlotID());
378                                                         useThis = true;
379                                                         break;
380                                                 }
381                                         }
382                                 }
383                                 if (!useThis && !mask)
384                                 {
385                                         const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
386                                         for (CAID_LIST::iterator ca(caids.begin()); ca != caids.end(); ++ca)
387                                         {
388                                                 std::vector<uint16_t>::const_iterator z =
389                                                         std::lower_bound(ci_caids.begin(), ci_caids.end(), *ca);
390                                                 if ( z != ci_caids.end() && *z == *ca )
391                                                 {
392                                                         eDebug("The CI in Slot %d has said it can handle caid %04x... so use it", ci_it->getSlotID(), *z);
393                                                         useThis = true;
394                                                         user_mapped = false;
395                                                         break;
396                                                 }
397                                         }
398                                 }
399                         }
400
401                         if (useThis)
402                         {
403                                 // check if this CI is already assigned to this pmthandler
404                                 eDVBCISlot *tmp = it->cislot;
405                                 while(tmp)
406                                 {
407                                         if (tmp == ci_it)
408                                                 break;
409                                         tmp=tmp->linked_next;
410                                 }
411                                 if (tmp) // ignore already assigned cislots...
412                                 {
413                                         eDebugCI("already assigned!");
414                                         continue;
415                                 }
416                                 eDebugCI("current slot %d usecount %d", ci_it->getSlotID(), ci_it->use_count);
417                                 if (ci_it->use_count)  // check if this CI can descramble more than one service
418                                 {
419                                         bool found = false;
420                                         useThis = false;
421                                         PMTHandlerList::iterator tmp = m_pmt_handlers.begin();
422                                         while (!found && tmp != m_pmt_handlers.end())
423                                         {
424                                                 eDebugCI(".");
425                                                 eDVBCISlot *tmp_cislot = tmp->cislot;
426                                                 while (!found && tmp_cislot)
427                                                 {
428                                                         eDebugCI("..");
429                                                         eServiceReferenceDVB ref2;
430                                                         tmp->pmthandler->getServiceReference(ref2);
431                                                         if ( tmp_cislot == ci_it && it->pmthandler != tmp->pmthandler )
432                                                         {
433                                                                 eDebugCI("check pmthandler %s for same service/tp", ref2.toString().c_str());
434                                                                 eDVBChannelID s1, s2;
435                                                                 if (ref != ref2)
436                                                                 {
437                                                                         eDebugCI("different services!");
438                                                                         ref.getChannelID(s1);
439                                                                         ref2.getChannelID(s2);
440                                                                 }
441                                                                 if (ref == ref2 || (s1 == s2 && canDescrambleMultipleServices(tmp_cislot->getSlotID())))
442                                                                 {
443                                                                         found = true;
444                                                                         eDebugCI("found!");
445                                                                         eDVBCISlot *tmpci = it->cislot = tmp->cislot;
446                                                                         while(tmpci)
447                                                                         {
448                                                                                 ++tmpci->use_count;
449                                                                                 eDebug("(2)CISlot %d, usecount now %d", tmpci->getSlotID(), tmpci->use_count);
450                                                                                 tmpci=tmpci->linked_next;
451                                                                         }
452                                                                 }
453                                                         }
454                                                         tmp_cislot=tmp_cislot->linked_next;
455                                                 }
456                                                 eDebugCI("...");
457                                                 ++tmp;
458                                         }
459                                 }
460
461                                 if (useThis)
462                                 {
463                                         if (ci_it->user_mapped)  // we dont like to link user mapped CIs
464                                         {
465                                                 eDebugCI("user mapped CI already in use... dont link!");
466                                                 continue;
467                                         }
468
469                                         ++ci_it->use_count;
470                                         eDebug("(1)CISlot %d, usecount now %d", ci_it->getSlotID(), ci_it->use_count);
471
472                                         data_source ci_source=CI_A;
473                                         switch(ci_it->getSlotID())
474                                         {
475                                                 case 0: ci_source = CI_A; break;
476                                                 case 1: ci_source = CI_B; break;
477                                                 case 2: ci_source = CI_C; break;
478                                                 case 3: ci_source = CI_D; break;
479                                                 default:
480                                                         eDebug("try to get source for CI %d!!\n", ci_it->getSlotID());
481                                                         break;
482                                         }
483
484                                         if (!it->cislot)
485                                         {
486                                                 int tunernum = -1;
487                                                 eUsePtr<iDVBChannel> channel;
488                                                 if (!pmthandler->getChannel(channel))
489                                                 {
490                                                         ePtr<iDVBFrontend> frontend;
491                                                         if (!channel->getFrontend(frontend))
492                                                         {
493                                                                 eDVBFrontend *fe = (eDVBFrontend*) &(*frontend);
494                                                                 tunernum = fe->getSlotID();
495                                                         }
496                                                 }
497                                                 ASSERT(tunernum != -1);
498                                                 data_source tuner_source = TUNER_A;
499                                                 switch (tunernum)
500                                                 {
501                                                         case 0: tuner_source = TUNER_A; break;
502                                                         case 1: tuner_source = TUNER_B; break;
503                                                         case 2: tuner_source = TUNER_C; break;
504                                                         case 3: tuner_source = TUNER_D; break;
505                                                         default:
506                                                                 eDebug("try to get source for tuner %d!!\n", tunernum);
507                                                                 break;
508                                                 }
509                                                 ci_it->current_tuner = tunernum;
510                                                 setInputSource(tunernum, ci_source);
511                                                 ci_it->setSource(tuner_source);
512                                         }
513                                         else
514                                         {
515                                                 ci_it->current_tuner = it->cislot->current_tuner;
516                                                 ci_it->linked_next = it->cislot;
517                                                 ci_it->setSource(ci_it->linked_next->current_source);
518                                                 ci_it->linked_next->setSource(ci_source);
519                                         }
520                                         it->cislot = ci_it;
521                                         eDebugCI("assigned!");
522                                         gotPMT(pmthandler);
523                                 }
524
525                                 if (it->cislot && user_mapped) // CI assigned to this pmthandler in this run.. and user mapped? then we break here.. we dont like to link other CIs to user mapped CIs
526                                 {
527                                         eDebugCI("user mapped CI assigned... dont link CIs!");
528                                         break;
529                                 }
530                         }
531                 }
532         }
533 }
534
535 void eDVBCIInterfaces::addPMTHandler(eDVBServicePMTHandler *pmthandler)
536 {
537         // check if this pmthandler is already registered
538         PMTHandlerList::iterator it = m_pmt_handlers.begin();
539         while (it != m_pmt_handlers.end())
540         {
541                 if ( *it++ == pmthandler )
542                         return;
543         }
544
545         eServiceReferenceDVB ref;
546         pmthandler->getServiceReference(ref);
547         eDebug("[eDVBCIInterfaces] addPMTHandler %s", ref.toString().c_str());
548
549         m_pmt_handlers.push_back(CIPmtHandler(pmthandler));
550         recheckPMTHandlers();
551 }
552
553 void eDVBCIInterfaces::removePMTHandler(eDVBServicePMTHandler *pmthandler)
554 {
555         PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(),m_pmt_handlers.end(),pmthandler);
556         if (it != m_pmt_handlers.end())
557         {
558                 eDVBCISlot *slot = it->cislot;
559                 eDVBServicePMTHandler *pmthandler = it->pmthandler;
560                 m_pmt_handlers.erase(it);
561
562                 eServiceReferenceDVB service_to_remove;
563                 pmthandler->getServiceReference(service_to_remove);
564
565                 bool sameServiceExist=false;
566                 for (PMTHandlerList::iterator i=m_pmt_handlers.begin(); i != m_pmt_handlers.end(); ++i)
567                 {
568                         if (i->cislot)
569                         {
570                                 eServiceReferenceDVB ref;
571                                 i->pmthandler->getServiceReference(ref);
572                                 if ( ref == service_to_remove )
573                                 {
574                                         sameServiceExist=true;
575                                         break;
576                                 }
577                         }
578                 }
579
580                 while(slot)
581                 {
582                         if (!sameServiceExist)
583                         {
584                                 if (slot->getNumOfServices() > 1)
585                                 {
586                                         eDebug("[eDVBCIInterfaces] remove last pmt handler for service %s send empty capmt",
587                                                 service_to_remove.toString().c_str());
588                                                 std::vector<uint16_t> caids;
589                                         caids.push_back(0xFFFF);
590                                         slot->sendCAPMT(pmthandler, caids);  // send a capmt without caids to remove a running service
591                                 }
592                                 slot->removeService(service_to_remove.getServiceID().get());
593                         }
594
595                         eDVBCISlot *next = slot->linked_next;
596                         if (!--slot->use_count)
597                         {
598                                 if (slot->linked_next)
599                                         slot->linked_next->setSource(slot->current_source);
600                                 else
601                                         setInputSource(slot->current_tuner, slot->current_source);
602
603                                 if (it->cislot == slot) // remove the base slot
604                                         it->cislot = slot->linked_next;
605                                 else
606                                 {
607                                         eDVBCISlot *tmp = it->cislot;
608                                         while(tmp->linked_next != slot)
609                                                 tmp = tmp->linked_next;
610                                         ASSERT(tmp);
611                                         if (slot->linked_next)
612                                                 tmp->linked_next = slot->linked_next;
613                                         else
614                                                 tmp->linked_next = 0;
615                                 }
616                                 slot->linked_next = 0;
617                                 slot->user_mapped = false;
618                         }
619                         eDebug("(3) slot %d usecount is now %d", slot->getSlotID(), slot->use_count);
620                         slot = next;
621                 }
622                 // check if another service is waiting for the CI
623                 recheckPMTHandlers();
624         }
625 }
626
627 void eDVBCIInterfaces::gotPMT(eDVBServicePMTHandler *pmthandler)
628 {
629         eDebug("[eDVBCIInterfaces] gotPMT");
630         PMTHandlerList::iterator it=std::find(m_pmt_handlers.begin(), m_pmt_handlers.end(), pmthandler);
631         if (it != m_pmt_handlers.end() && it->cislot)
632         {
633                 eDVBCISlot *tmp = it->cislot;
634                 while(tmp)
635                 {
636                         eDebugCI("check slot %d %d %d", tmp->getSlotID(), tmp->running_services.empty(), canDescrambleMultipleServices(tmp->getSlotID()));
637                         if (tmp->running_services.empty() || canDescrambleMultipleServices(tmp->getSlotID()))
638                                 tmp->sendCAPMT(pmthandler);
639                         tmp = tmp->linked_next;
640                 }
641         }
642 }
643
644 int eDVBCIInterfaces::getMMIState(int slotid)
645 {
646         eDVBCISlot *slot;
647
648         if( (slot = getSlot(slotid)) == 0 )
649                 return -1;
650
651         return slot->getMMIState();
652 }
653
654 int eDVBCIInterfaces::setInputSource(int tuner_no, data_source source)
655 {
656 //      eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
657 //      eDebug("eDVBCIInterfaces::setInputSource(%d %d)", tuner_no, (int)source);
658         if (getNumOfSlots() > 1) // FIXME .. we force DM8000 when more than one CI Slot is avail
659         {
660                 char buf[64];
661                 snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
662
663                 FILE *input=0;
664                 if((input = fopen(buf, "wb")) == NULL) {
665                         eDebug("cannot open %s", buf);
666                         return 0;
667                 }
668
669                 if (tuner_no > 3)
670                         eDebug("setInputSource(%d, %d) failed... dm8000 just have four inputs", tuner_no, (int)source);
671
672                 switch(source)
673                 {
674                         case CI_A:
675                                 fprintf(input, "CI0");
676                                 break;
677                         case CI_B:
678                                 fprintf(input, "CI1");
679                                 break;
680                         case CI_C:
681                                 fprintf(input, "CI2");
682                         break;
683                         case CI_D:
684                                 fprintf(input, "CI3");
685                                 break;
686                         case TUNER_A:
687                                 fprintf(input, "A");
688                                 break;
689                         case TUNER_B:
690                                 fprintf(input, "B");
691                                 break;
692                         case TUNER_C:
693                                 fprintf(input, "C");
694                                 break;
695                         case TUNER_D:
696                                 fprintf(input, "D");
697                                 break;
698                         default:
699                                 eDebug("setInputSource for input %d failed!!!\n", (int)source);
700                                 break;
701                 }
702
703                 fclose(input);
704         }
705         else  // DM7025
706         {
707                 char buf[64];
708                 snprintf(buf, 64, "/proc/stb/tsmux/input%d", tuner_no);
709
710                 if (tuner_no > 1)
711                         eDebug("setInputSource(%d, %d) failed... dm7025 just have two inputs", tuner_no, (int)source);
712
713                 FILE *input=0;
714                 if((input = fopen(buf, "wb")) == NULL) {
715                         eDebug("cannot open %s", buf);
716                         return 0;
717                 }
718
719                 switch(source)
720                 {
721                         case CI_A:
722                                 fprintf(input, "CI");
723                                 break;
724                         case TUNER_A:
725                                 fprintf(input, "A");
726                                 break;
727                         case TUNER_B:
728                                 fprintf(input, "B");
729                                 break;
730                         default:
731                                 eDebug("setInputSource for input %d failed!!!\n", (int)source);
732                                 break;
733                 }
734
735                 fclose(input);
736         }
737         eDebug("eDVBCIInterfaces->setInputSource(%d, %d)", tuner_no, (int)source);
738         return 0;
739 }
740
741 PyObject *eDVBCIInterfaces::getDescrambleRules(int slotid)
742 {
743         eDVBCISlot *slot = getSlot(slotid);
744         if (!slot)
745         {
746                 char tmp[255];
747                 snprintf(tmp, 255, "eDVBCIInterfaces::getDescrambleRules try to get rules for CI Slot %d... but just %d slots are available", slotid, m_slots.size());
748                 PyErr_SetString(PyExc_StandardError, tmp);
749                 return 0;
750         }
751         ePyObject tuple = PyTuple_New(3);
752         int caids = slot->possible_caids.size();
753         int services = slot->possible_services.size();
754         int providers = slot->possible_providers.size();
755         ePyObject caid_list = PyList_New(caids);
756         ePyObject service_list = PyList_New(services);
757         ePyObject provider_list = PyList_New(providers);
758         caidSet::iterator caid_it(slot->possible_caids.begin());
759         while(caids)
760         {
761                 --caids;
762                 PyList_SET_ITEM(caid_list, caids, PyLong_FromLong(*caid_it));
763                 ++caid_it;
764         }
765         serviceSet::iterator ref_it(slot->possible_services.begin());
766         while(services)
767         {
768                 --services;
769                 PyList_SET_ITEM(service_list, services, PyString_FromString(ref_it->toString().c_str()));
770                 ++ref_it;
771         }
772         providerSet::iterator provider_it(slot->possible_providers.begin());
773         while(providers)
774         {
775                 ePyObject tuple = PyTuple_New(2);
776                 PyTuple_SET_ITEM(tuple, 0, PyString_FromString(provider_it->first.c_str()));
777                 PyTuple_SET_ITEM(tuple, 1, PyLong_FromUnsignedLong(provider_it->second));
778                 --providers;
779                 PyList_SET_ITEM(provider_list, providers, tuple);
780                 ++provider_it;
781         }
782         PyTuple_SET_ITEM(tuple, 0, service_list);
783         PyTuple_SET_ITEM(tuple, 1, provider_list);
784         PyTuple_SET_ITEM(tuple, 2, caid_list);
785         return tuple;
786 }
787
788 const char *PyObject_TypeStr(PyObject *o)
789 {
790         return o->ob_type && o->ob_type->tp_name ? o->ob_type->tp_name : "unknown object type";
791 }
792
793 RESULT eDVBCIInterfaces::setDescrambleRules(int slotid, SWIG_PYOBJECT(ePyObject) obj )
794 {
795         eDVBCISlot *slot = getSlot(slotid);
796         if (!slot)
797         {
798                 char tmp[255];
799                 snprintf(tmp, 255, "eDVBCIInterfaces::setDescrambleRules try to set rules for CI Slot %d... but just %d slots are available", slotid, m_slots.size());
800                 PyErr_SetString(PyExc_StandardError, tmp);
801                 return -1;
802         }
803         if (!PyTuple_Check(obj))
804         {
805                 char tmp[255];
806                 snprintf(tmp, 255, "2nd argument of setDescrambleRules is not a tuple.. it is a '%s'!!", PyObject_TypeStr(obj));
807                 PyErr_SetString(PyExc_StandardError, tmp);
808                 return -1;
809         }
810         if (PyTuple_Size(obj) != 3)
811         {
812                 const char *errstr = "eDVBCIInterfaces::setDescrambleRules not enough entrys in argument tuple!!\n"
813                         "first argument should be a pythonlist with possible services\n"
814                         "second argument should be a pythonlist with possible providers/dvbnamespace tuples\n"
815                         "third argument should be a pythonlist with possible caids";
816                 PyErr_SetString(PyExc_StandardError, errstr);
817                 return -1;
818         }
819         ePyObject service_list = PyTuple_GET_ITEM(obj, 0);
820         ePyObject provider_list = PyTuple_GET_ITEM(obj, 1);
821         ePyObject caid_list = PyTuple_GET_ITEM(obj, 2);
822         if (!PyList_Check(service_list) || !PyList_Check(provider_list) || !PyList_Check(caid_list))
823         {
824                 char errstr[512];
825                 snprintf(errstr, 512, "eDVBCIInterfaces::setDescrambleRules incorrect data types in argument tuple!!\n"
826                         "first argument(%s) should be a pythonlist with possible services (reference strings)\n"
827                         "second argument(%s) should be a pythonlist with possible providers (providername strings)\n"
828                         "third argument(%s) should be a pythonlist with possible caids (ints)",
829                         PyObject_TypeStr(service_list), PyObject_TypeStr(provider_list), PyObject_TypeStr(caid_list));
830                 PyErr_SetString(PyExc_StandardError, errstr);
831                 return -1;
832         }
833         slot->possible_caids.clear();
834         slot->possible_services.clear();
835         slot->possible_providers.clear();
836         int size = PyList_Size(service_list);
837         while(size)
838         {
839                 --size;
840                 ePyObject refstr = PyList_GET_ITEM(service_list, size);
841                 if (!PyString_Check(refstr))
842                 {
843                         char buf[255];
844                         snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in service list is not a string.. it is '%s'!!", PyObject_TypeStr(refstr));
845                         PyErr_SetString(PyExc_StandardError, buf);
846                         return -1;
847                 }
848                 char *tmpstr = PyString_AS_STRING(refstr);
849                 eServiceReference ref(tmpstr);
850                 if (ref.valid())
851                         slot->possible_services.insert(ref);
852                 else
853                         eDebug("eDVBCIInterfaces::setDescrambleRules '%s' is not a valid service reference... ignore!!", tmpstr);
854         };
855         size = PyList_Size(provider_list);
856         while(size)
857         {
858                 --size;
859                 ePyObject tuple = PyList_GET_ITEM(provider_list, size);
860                 if (!PyTuple_Check(tuple))
861                 {
862                         char buf[255];
863                         snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in provider list is not a tuple it is '%s'!!", PyObject_TypeStr(tuple));
864                         PyErr_SetString(PyExc_StandardError, buf);
865                         return -1;
866                 }
867                 if (PyTuple_Size(tuple) != 2)
868                 {
869                         char buf[255];
870                         snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules provider tuple has %d instead of 2 entries!!", PyTuple_Size(tuple));
871                         PyErr_SetString(PyExc_StandardError, buf);
872                         return -1;
873                 }
874                 if (!PyString_Check(PyTuple_GET_ITEM(tuple, 0)))
875                 {
876                         char buf[255];
877                         snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules 1st entry in provider tuple is not a string it is '%s'", PyObject_TypeStr(PyTuple_GET_ITEM(tuple, 0)));
878                         PyErr_SetString(PyExc_StandardError, buf);
879                         return -1;
880                 }
881                 if (!PyLong_Check(PyTuple_GET_ITEM(tuple, 1)))
882                 {
883                         char buf[255];
884                         snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules 2nd entry in provider tuple is not a long it is '%s'", PyObject_TypeStr(PyTuple_GET_ITEM(tuple, 1)));
885                         PyErr_SetString(PyExc_StandardError, buf);
886                         return -1;
887                 }
888                 char *tmpstr = PyString_AS_STRING(PyTuple_GET_ITEM(tuple, 0));
889                 uint32_t orbpos = PyLong_AsUnsignedLong(PyTuple_GET_ITEM(tuple, 1));
890                 if (strlen(tmpstr))
891                         slot->possible_providers.insert(std::pair<std::string, uint32_t>(tmpstr, orbpos));
892                 else
893                         eDebug("eDVBCIInterfaces::setDescrambleRules ignore invalid entry in provider tuple (string is empty)!!");
894         };
895         size = PyList_Size(caid_list);
896         while(size)
897         {
898                 --size;
899                 ePyObject caid = PyList_GET_ITEM(caid_list, size);
900                 if (!PyInt_Check(caid))
901                 {
902                         char buf[255];
903                         snprintf(buf, 255, "eDVBCIInterfaces::setDescrambleRules entry in caid list is not a long it is '%s'!!", PyObject_TypeStr(caid));
904                         PyErr_SetString(PyExc_StandardError, buf);
905                         return -1;
906                 }
907                 int tmpcaid = PyInt_AsLong(caid);
908                 if (tmpcaid > 0 && tmpcaid < 0x10000)
909                         slot->possible_caids.insert(tmpcaid);
910                 else
911                         eDebug("eDVBCIInterfaces::setDescrambleRules %d is not a valid caid... ignore!!", tmpcaid);
912         };
913         return 0;
914 }
915
916 PyObject *eDVBCIInterfaces::readCICaIds(int slotid)
917 {
918         eDVBCISlot *slot = getSlot(slotid);
919         if (!slot)
920         {
921                 char tmp[255];
922                 snprintf(tmp, 255, "eDVBCIInterfaces::readCICaIds try to get CAIds for CI Slot %d... but just %d slots are available", slotid, m_slots.size());
923                 PyErr_SetString(PyExc_StandardError, tmp);
924         }
925         else
926         {
927                 int idx=0;
928                 eDVBCICAManagerSession *ca_manager = slot->getCAManager();
929                 const std::vector<uint16_t> &ci_caids = ca_manager->getCAIDs();
930                 ePyObject list = PyList_New(ci_caids.size());
931                 for (std::vector<uint16_t>::const_iterator it = ci_caids.begin(); it != ci_caids.end(); ++it)
932                         PyList_SET_ITEM(list, idx++, PyLong_FromLong(*it));
933                 return list;
934         }
935         return 0;
936 }
937
938 int eDVBCISlot::send(const unsigned char *data, size_t len)
939 {
940         int res=0;
941         //int i;
942         //eDebugNoNewLine("< ");
943         //for(i=0;i<len;i++)
944         //      eDebugNoNewLine("%02x ",data[i]);
945         //eDebug("");
946
947         if (sendqueue.empty())
948                 res = ::write(fd, data, len);
949
950         if (res < 0 || (unsigned int)res != len)
951         {
952                 unsigned char *d = new unsigned char[len];
953                 memcpy(d, data, len);
954                 sendqueue.push( queueData(d, len) );
955                 notifier->setRequested(eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
956         }
957
958         return res;
959 }
960
961 void eDVBCISlot::data(int what)
962 {
963         eDebugCI("CISlot %d what %d\n", getSlotID(), what);
964         if(what == eSocketNotifier::Priority) {
965                 if(state != stateRemoved) {
966                         state = stateRemoved;
967                         while(sendqueue.size())
968                         {
969                                 delete [] sendqueue.top().data;
970                                 sendqueue.pop();
971                         }
972                         eDVBCISession::deleteSessions(this);
973                         eDVBCIInterfaces::getInstance()->ciRemoved(this);
974                         notifier->setRequested(eSocketNotifier::Read);
975                         eDVBCI_UI::getInstance()->setState(getSlotID(),0);
976                 }
977                 return;
978         }
979
980         if (state == stateInvalid)
981                 reset();
982
983         if(state != stateInserted) {
984                 eDebug("ci inserted in slot %d", getSlotID());
985                 state = stateInserted;
986                 eDVBCI_UI::getInstance()->setState(getSlotID(),1);
987                 notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
988                 /* enable PRI to detect removal or errors */
989         }
990
991         if (what & eSocketNotifier::Read) {
992                 __u8 data[4096];
993                 int r;
994                 r = ::read(fd, data, 4096);
995                 if(r > 0) {
996 //                      int i;
997 //                      eDebugNoNewLine("> ");
998 //                      for(i=0;i<r;i++)
999 //                              eDebugNoNewLine("%02x ",data[i]);
1000 //                      eDebug("");
1001                         eDVBCISession::receiveData(this, data, r);
1002                         eDVBCISession::pollAll();
1003                         return;
1004                 }
1005         }
1006         else if (what & eSocketNotifier::Write) {
1007                 if (!sendqueue.empty()) {
1008                         const queueData &qe = sendqueue.top();
1009                         int res = ::write(fd, qe.data, qe.len);
1010                         if (res >= 0 && (unsigned int)res == qe.len)
1011                         {
1012                                 delete [] qe.data;
1013                                 sendqueue.pop();
1014                         }
1015                 }
1016                 else
1017                         notifier->setRequested(eSocketNotifier::Read|eSocketNotifier::Priority);
1018         }
1019 }
1020
1021 DEFINE_REF(eDVBCISlot);
1022
1023 eDVBCISlot::eDVBCISlot(eMainloop *context, int nr)
1024 {
1025         char filename[128];
1026
1027         application_manager = 0;
1028         mmi_session = 0;
1029         ca_manager = 0;
1030         use_count = 0;
1031         linked_next = 0;
1032         user_mapped = false;
1033         first_plugged = true;
1034         
1035         slotid = nr;
1036
1037         sprintf(filename, "/dev/ci%d", nr);
1038
1039 //      possible_caids.insert(0x1702);
1040 //      possible_providers.insert(providerPair("PREMIERE", 0xC00000));
1041 //      possible_services.insert(eServiceReference("1:0:1:2A:4:85:C00000:0:0:0:"));
1042
1043         fd = ::open(filename, O_RDWR | O_NONBLOCK);
1044
1045         eDebugCI("CI Slot %d has fd %d", getSlotID(), fd);
1046         state = stateInvalid;
1047
1048         if (fd >= 0)
1049         {
1050                 notifier = eSocketNotifier::create(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write);
1051                 CONNECT(notifier->activated, eDVBCISlot::data);
1052         } else
1053         {
1054                 perror(filename);
1055         }
1056 }
1057
1058 eDVBCISlot::~eDVBCISlot()
1059 {
1060         eDVBCISession::deleteSessions(this);
1061 }
1062
1063 void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session )
1064 {
1065         application_manager=session;
1066 }
1067
1068 void eDVBCISlot::setMMIManager( eDVBCIMMISession *session )
1069 {
1070         mmi_session = session;
1071 }
1072
1073 void eDVBCISlot::setCAManager( eDVBCICAManagerSession *session )
1074 {
1075         ca_manager = session;
1076 }
1077
1078 int eDVBCISlot::getSlotID()
1079 {
1080         return slotid;
1081 }
1082
1083 int eDVBCISlot::reset()
1084 {
1085         eDebug("CI Slot %d: reset requested", getSlotID());
1086
1087         if (state == stateInvalid)
1088         {
1089                 unsigned char buf[256];
1090                 eDebug("ci flush");
1091                 while(::read(fd, buf, 256)>0);
1092                 state = stateResetted;
1093         }
1094
1095         while(sendqueue.size())
1096         {
1097                 delete [] sendqueue.top().data;
1098                 sendqueue.pop();
1099         }
1100
1101         ioctl(fd, 0);
1102
1103         return 0;
1104 }
1105
1106 int eDVBCISlot::startMMI()
1107 {
1108         eDebug("CI Slot %d: startMMI()", getSlotID());
1109         
1110         if(application_manager)
1111                 application_manager->startMMI();
1112         
1113         return 0;
1114 }
1115
1116 int eDVBCISlot::stopMMI()
1117 {
1118         eDebug("CI Slot %d: stopMMI()", getSlotID());
1119
1120         if(mmi_session)
1121                 mmi_session->stopMMI();
1122         
1123         return 0;
1124 }
1125
1126 int eDVBCISlot::answerText(int answer)
1127 {
1128         eDebug("CI Slot %d: answerText(%d)", getSlotID(), answer);
1129
1130         if(mmi_session)
1131                 mmi_session->answerText(answer);
1132
1133         return 0;
1134 }
1135
1136 int eDVBCISlot::getMMIState()
1137 {
1138         if(mmi_session)
1139                 return 1;
1140
1141         return 0;
1142 }
1143
1144 int eDVBCISlot::answerEnq(char *value)
1145 {
1146         eDebug("CI Slot %d: answerENQ(%s)", getSlotID(), value);
1147
1148         if(mmi_session)
1149                 mmi_session->answerEnq(value);
1150
1151         return 0;
1152 }
1153
1154 int eDVBCISlot::cancelEnq()
1155 {
1156         eDebug("CI Slot %d: cancelENQ", getSlotID());
1157
1158         if(mmi_session)
1159                 mmi_session->cancelEnq();
1160
1161         return 0;
1162 }
1163
1164 int eDVBCISlot::sendCAPMT(eDVBServicePMTHandler *pmthandler, const std::vector<uint16_t> &ids)
1165 {
1166         if (!ca_manager)
1167         {
1168                 eDebug("no ca_manager (no CI plugged?)");
1169                 return -1;
1170         }
1171         const std::vector<uint16_t> &caids = ids.empty() ? ca_manager->getCAIDs() : ids;
1172         ePtr<eTable<ProgramMapSection> > ptr;
1173         if (pmthandler->getPMT(ptr))
1174                 return -1;
1175         else
1176         {
1177                 eDVBTableSpec table_spec;
1178                 ptr->getSpec(table_spec);
1179                 int pmt_version = table_spec.version & 0x1F; // just 5 bits
1180
1181                 eServiceReferenceDVB ref;
1182                 pmthandler->getServiceReference(ref);
1183                 uint16_t program_number = ref.getServiceID().get();
1184                 std::map<uint16_t, uint8_t>::iterator it =
1185                         running_services.find(program_number);
1186
1187                 if ( it != running_services.end() &&
1188                         (pmt_version == it->second) &&
1189                         !(caids.size() == 1 && caids[0] == 0xFFFF) )
1190                 {
1191                         eDebug("[eDVBCISlot] dont send self capmt version twice");
1192                         return -1;
1193                 }
1194
1195                 std::vector<ProgramMapSection*>::const_iterator i=ptr->getSections().begin();
1196                 if ( i == ptr->getSections().end() )
1197                         return -1;
1198                 else
1199                 {
1200                         unsigned char raw_data[2048];
1201
1202 //                      eDebug("send %s capmt for service %04x to slot %d",
1203 //                              it != running_services.end() ? "UPDATE" : running_services.empty() ? "ONLY" : "ADD",
1204 //                              program_number, slotid);
1205
1206                         CaProgramMapSection capmt(*i++,
1207                                 it != running_services.end() ? 0x05 /*update*/ : running_services.empty() ? 0x03 /*only*/ : 0x04 /*add*/, 0x01, caids );
1208                         while( i != ptr->getSections().end() )
1209                         {
1210                 //                      eDebug("append");
1211                                 capmt.append(*i++);
1212                         }
1213                         capmt.writeToBuffer(raw_data);
1214 #if 1
1215 // begin calc capmt length
1216                         int wp=0;
1217                         int hlen;
1218                         if ( raw_data[3] & 0x80 )
1219                         {
1220                                 int i=0;
1221                                 int lenbytes = raw_data[3] & ~0x80;
1222                                 while(i < lenbytes)
1223                                         wp = (wp << 8) | raw_data[4 + i++];
1224                                 wp+=4;
1225                                 wp+=lenbytes;
1226                                 hlen = 4 + lenbytes;
1227                         }
1228                         else
1229                         {
1230                                 wp = raw_data[3];
1231                                 wp+=4;
1232                                 hlen = 4;
1233                         }
1234 // end calc capmt length
1235 //                      eDebug("ca_manager %p dump capmt:", ca_manager);
1236 //                      for(int i=0;i<wp;i++)
1237 //                              eDebugNoNewLine("%02x ", raw_data[i]);
1238 //                      eDebug("");
1239 #endif
1240                         if (caids.size() == 1 && caids[0] == 0xFFFF)
1241                         {
1242 //                              eDebugNoNewLine("SEND EMPTY CAPMT.. old version is %02x", raw_data[hlen+3]);
1243                                 raw_data[hlen+3] &= ~0x3E;
1244                                 raw_data[hlen+3] |= ((pmt_version+1) & 0x1F) << 1;
1245 //                              eDebug(" new version is %02x", raw_data[hlen+3]);
1246                         }
1247
1248                         //dont need tag and lenfield
1249                         ca_manager->sendCAPMT(raw_data + hlen, wp - hlen);
1250                         running_services[program_number] = pmt_version;
1251                 }
1252         }
1253         return 0;
1254 }
1255
1256 void eDVBCISlot::removeService(uint16_t program_number)
1257 {
1258         if (program_number == 0xFFFF)
1259                 running_services.clear();  // remove all
1260         else
1261                 running_services.erase(program_number);  // remove single service
1262 }
1263
1264 int eDVBCISlot::setSource(data_source source)
1265 {
1266         current_source = source;
1267         if (eDVBCIInterfaces::getInstance()->getNumOfSlots() > 1) // FIXME .. we force DM8000 when more than one CI Slot is avail
1268         {
1269                 char buf[64];
1270                 snprintf(buf, 64, "/proc/stb/tsmux/ci%d_input", slotid);
1271                 FILE *ci = fopen(buf, "wb");
1272                 switch(source)
1273                 {
1274                         case CI_A:
1275                                 fprintf(ci, "CI0");
1276                                 break;
1277                         case CI_B:
1278                                 fprintf(ci, "CI1");
1279                                 break;
1280                         case CI_C:
1281                                 fprintf(ci, "CI2");
1282                                 break;
1283                         case CI_D:
1284                                 fprintf(ci, "CI3");
1285                                 break;
1286                         case TUNER_A:
1287                                 fprintf(ci, "A");
1288                                 break;
1289                         case TUNER_B:
1290                                 fprintf(ci, "B");
1291                                 break;
1292                         case TUNER_C:
1293                                 fprintf(ci, "C");
1294                                 break;
1295                                 case TUNER_D:
1296                                 fprintf(ci, "D");
1297                                 break;
1298                         default:
1299                                 eDebug("CI Slot %d: setSource %d failed!!!\n", getSlotID(), (int)source);
1300                                 break;
1301                 }
1302                 fclose(ci);
1303         }
1304         else // DM7025
1305         {
1306 //              eDebug("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
1307 //              eDebug("eDVBCISlot::enableTS(%d %d)", enable, (int)source);
1308                 FILE *ci = fopen("/proc/stb/tsmux/input2", "wb");
1309                 if(ci == NULL) {
1310                         eDebug("cannot open /proc/stb/tsmux/input2");
1311                         return 0;
1312                 }
1313                 if (source != TUNER_A && source != TUNER_B)
1314                         eDebug("CI Slot %d: setSource %d failed!!!\n", getSlotID(), (int)source);
1315                 else
1316                         fprintf(ci, "%s", source==TUNER_A ? "A" : "B");  // configure CI data source (TunerA, TunerB)
1317                 fclose(ci);
1318         }
1319         eDebug("CI Slot %d setSource(%d)", getSlotID(), (int)source);
1320         return 0;
1321 }
1322
1323 eAutoInitP0<eDVBCIInterfaces> init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots");