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