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