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