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