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