trunk 20080912
[gitenigma.git] / lib / dvb / dvbci.cpp
blobcb15e67129be9df053b783dc8a5d16fb92b9ff99
1 #ifndef DISABLE_CI
2 #include <lib/dvb/dvbci.h>
3 #include <lib/dvb/dvbservice.h>
4 #include <lib/dvb/si.h>
5 #include <lib/base/i18n.h>
6 #include <lib/system/init.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/ioctl.h>
11 #include <errno.h>
13 //external defines (because missing dreambox header-files in cvs)
14 #define CI_RESET 0
15 #define CI_SOFTRESET 1
16 #define CI_GET_BUFFERSIZE 2
17 #define CI_GET_STATUS 3
18 #define CI_TS_ACTIVATE 6
19 #define CI_TS_DEACTIVATE 7
21 #define MAX_SESSIONS 32
22 #define STATE_FREE 0
23 #define STATE_OPEN 1
25 int eDVBCI::instance_count=0;
27 eDVBCI::eDVBCI()
28 :pollTimer(this), caidcount(0), ml_bufferlen(0), messages(this, 1)
30 instance_count++;
32 state=stateInit;
34 eDebug("[DVBCI] start");
36 if (instance_count == 1)
37 fd=::open("/dev/ci",O_RDWR|O_NONBLOCK);
38 else
39 fd=::open("/dev/ci1",O_RDWR|O_NONBLOCK);
41 if (fd<0)
43 if (instance_count == 1)
44 eDebug("[DVBCI] error opening /dev/ci");
45 else
46 eDebug("[DVBCI] error opening /dev/ci1");
48 state=stateError;
51 if(state!=stateError)
53 ci=new eSocketNotifier(this, fd, eSocketNotifier::Read, 0);
54 CONNECT(ci->activated, eDVBCI::dataAvailable);
57 CONNECT(pollTimer.timeout,eDVBCI::poll);
59 CONNECT(messages.recv_msg, eDVBCI::gotMessage);
61 strcpy(appName, _("no module"));
62 tempPMTentrys=0;
64 for (int i=0; i < MAXTRANSPORTSESSIONS; ++i)
66 lpduReceiveQueues[i].numLPDUS=0;
67 lpduReceiveQueues[i].firstLPDU=NULL;
70 run();
73 void eDVBCI::thread()
75 exec();
76 pollTimer.stop();
79 eDVBCI::~eDVBCI()
81 messages.send(eDVBCIMessage(eDVBCIMessage::exit));
82 kill();
83 delete ci;
84 if (fd >= 0)
85 close(fd);
86 instance_count--;
89 void eDVBCI::gotMessage(const eDVBCIMessage &message)
91 switch (message.type)
93 case eDVBCIMessage::start:
94 if (state == stateInit)
96 ci->start();
97 ci_state=0;
99 dataAvailable(0);
100 break;
101 case eDVBCIMessage::reset:
102 // eDebug("[DVBCI] got reset message..");
103 while(sendqueue.size())
105 delete [] sendqueue.top().data;
106 sendqueue.pop();
108 if(!ci_state)
110 strcpy(appName,_("no module"));
111 ci_progress(appName);
113 ci_state=0;
114 clearCAIDs();
115 // if (::ioctl(fd,CI_RESET)<0 )
116 // eDebug("CI_RESET failed (%m)");
117 dataAvailable(1000); // force reset
118 break;
119 case eDVBCIMessage::init:
120 // eDebug("[DVBCI] got init message..");
121 if(ci_state)
123 versions.clear();
124 newService();
126 else
128 strcpy(appName,_("no module"));
129 ci_progress(appName);
131 break;
132 case eDVBCIMessage::go:
133 newService();
134 break;
135 case eDVBCIMessage::mmi_begin:
136 // eDebug("[DVBCI] got mmi_begin message..");
137 mmi_begin();
138 break;
139 case eDVBCIMessage::mmi_end:
140 // eDebug("[DVBCI] got mmi_end message..");
141 mmi_end();
142 break;
143 case eDVBCIMessage::mmi_enqansw:
144 // eDebug("[DVBCI] got mmi_answ message..");
145 mmi_enqansw(message.data);
146 delete[] message.data;
147 break;
148 case eDVBCIMessage::mmi_menuansw:
149 // eDebug("[DVBCI] got mmi_menu_answ message..");
150 mmi_menuansw((int)message.sid);
151 break;
152 case eDVBCIMessage::exit:
153 // eDebug("[DVBCI] got exit message..");
154 quit();
155 break;
156 case eDVBCIMessage::getcaids:
157 // eDebug("[DVBCI] got getcaids message..");
158 pushCAIDs();
159 break;
160 case eDVBCIMessage::PMTflush:
161 // eDebug("[DVBCI] got PMTflush message..");
162 PMTflush(message.sid);
163 break;
164 case eDVBCIMessage::PMTaddPID:
165 // eDebug("[DVBCI] got PMTaddPID message..");
166 // eDebug("addPID %04x, type %02x", message.pid, message.streamtype );
167 PMTaddPID(message.sid,message.pid,message.streamtype);
168 break;
169 case eDVBCIMessage::PMTsetVersion:
170 PMTsetVersion(message.sid, message.pid);
171 break;
172 case eDVBCIMessage::PMTaddDescriptor:
173 // eDebug("[DVBCI] got PMTaddDescriptor message..");
174 // eDebug("addDescr len %02x", message.data[1]+2);
175 // for (int i=0; i < message.data[1]+2; ++i)
176 // eDebugNoNewLine("%02x ", message.data[i]);
177 // eDebug("");
178 PMTaddDescriptor(message.sid, message.data);
179 break;
180 case eDVBCIMessage::getAppName:
181 ci_progress(appName);
182 break;
184 // disabled... see dvbservice.cpp for more info
186 case eDVBCIMessage::enable_ts:
188 int present=0;
190 stopTimer();
192 if (::ioctl(fd,CI_GET_STATUS,&present)<0)
194 eDebug("CI_GET_STATUS failed (%m)");
195 break;
198 if( present )
200 if ( ::ioctl(fd, CI_TS_ACTIVATE) < 0 )
201 eDebug("CI_TS_ACTIVATE failed (%m)");
203 break;
205 case eDVBCIMessage::disable_ts:
206 if ( ::ioctl(fd, CI_TS_DEACTIVATE) < 0 )
207 eDebug("CI_TS_DEACTIVATE failed (%m)");
208 break;
213 void eDVBCI::mmi_begin()
215 unsigned char buffer[10];
217 // eDebug("start mmi");
218 memcpy(buffer,"\x90\x2\x0\x2\x9f\x80\x22\x0",8);
219 sendTPDU(0xA0,8,1,buffer);
222 void eDVBCI::mmi_end()
224 unsigned char buffer[10];
226 // eDebug("stop mmi");
227 memcpy(buffer,"\x90\x2\x0\x4\x9f\x88\x00\x00",8);
228 sendTPDU(0xA0,8,1,buffer);
231 void eDVBCI::mmi_enqansw(unsigned char *buf)
233 // eDebug("got mmi_answer");
234 unsigned char buffer[ buf[0]+8 ];
235 memcpy(buffer,"\x90\x2\x0\x4\x9f\x88\x08",7);
236 memcpy(buffer+7, buf, buf[0]+1 );
238 int i=1;
239 for(;i<MAX_SESSIONS;++i) // search mmi session .. hope it exist only one :)
240 if(sessions[i].state && sessions[i].service_class==0x400041)
242 buffer[3]=i; // session
243 sendTPDU(0xA0,buf[0]+8,1,buffer);
244 #if 0
245 for (int i=0; i < buf[0]+8; ++i )
246 eDebugNoNewLine("%02x ", buffer[i]);
247 eDebug("");
248 #endif
249 break;
251 if ( i == MAX_SESSIONS )
252 eDebug("[DVBCI] no mmi session found(enq) !");
255 void eDVBCI::mmi_menuansw(int val)
257 // eDebug("got mmi_menu_answer %d",val);
258 unsigned char buffer[9];
259 memcpy(buffer,"\x90\x2\x0\x4\x9f\x88\x0B\x1",8);
261 int i=1;
262 for(;i<MAX_SESSIONS;++i) // search mmi session .. hope it exist only one :)
263 if(sessions[i].state && sessions[i].service_class==0x400041)
265 buffer[3]=i;
266 buffer[8]=val&0xff;
267 sendTPDU(0xA0,9,1,buffer);
268 break;
270 if ( i == MAX_SESSIONS )
271 eDebug("[DVBCI] no mmi session found!");
274 void eDVBCI::PMTsetVersion(int sid, int version)
276 for (CIServiceMap::iterator it( services.begin() );
277 it != services.end(); ++it )
279 if ( it->first == sid )
281 for (std::list<tempPMT_t>::iterator i( it->second.begin() );
282 i != it->second.end(); )
284 if ( i->type == 2 )
285 delete [] i->descriptor;
286 i = it->second.erase(i);
288 break;
291 tempPMT_t tmp;
292 tmp.type=0;
293 tmp.version=version;
294 services[sid].push_back(tmp);
297 void eDVBCI::PMTflush(int sid)
299 for (CIServiceMap::iterator it( services.begin() );
300 it != services.end(); )
302 if ( it->first == sid || sid == -1 )
304 bool scrambled=false;
305 std::map<int,int>::iterator d = versions.find(it->first);
306 if ( d != versions.end() )
308 for (std::list<tempPMT_t>::iterator i( it->second.begin() );
309 i != it->second.end(); )
311 if ( i->type == 2 )
313 delete [] i->descriptor;
314 i = it->second.erase(i);
315 scrambled=true;
317 else
318 ++i;
320 if (scrambled)
322 int oldvers = d->second;
323 it->second.front().version=((oldvers&0xC1)|((oldvers+2)&0x3E));
324 newService(); // i hope the ci give now this "slot" free
328 versions.erase(it->first); // remove from last send version map
330 services.erase(it++); // remove from known service map
331 if ( sid != -1 )
332 break; // the only one service is flushed.. break now
334 else
335 ++it;
339 void eDVBCI::PMTaddPID(int sid, int pid, int streamtype)
341 //eDebug("got new PID:%x",pid);
343 tempPMT_t entry;
344 entry.type = 1;
345 entry.streamtype = streamtype;
346 entry.pid=pid;
347 services[sid].push_back(entry);
350 void eDVBCI::PMTaddDescriptor(int sid, unsigned char *data)
352 //eDebug("got new CA-Descr. for CAID:%.2x%.2x",data[2],data[3]);
353 tempPMT_t entry;
354 entry.type = 2;
355 entry.descriptor = data;
356 services[sid].push_back(entry);
359 void eDVBCI::newService()
361 //eDebug("got new %d PMT entrys",tempPMTentrys);
362 ci_progress(appName);
363 unsigned char capmt[2048];
365 memcpy(capmt,"\x90\x2\x0\x3\x9f\x80\x32",7); //session nr.3 & capmt-tag
367 unsigned int cnt=0;
368 for (std::map<int, std::list<tempPMT_t> >::iterator it = services.begin();
369 it != services.end(); ++it )
371 cnt++;
372 capmt[7]=0x81;
374 if ( !versions.size() )
375 capmt[9] = 0x03; // only
376 else
378 std::map<int,int>::iterator i = versions.find(it->first);
379 if ( i != versions.end() )
381 if (it->second.front().version != i->second)
382 capmt[9]=0x05; // update
383 else
384 continue; // this is the same pmt version.. don't send..
386 else
387 capmt[9]=0x04; // new service.. add
390 // store new PMT version
391 versions[it->first]=it->second.front().version;
393 // eDebug("ca_pmt_list_management = %d", capmt[9]);
395 capmt[10]=(unsigned char)((it->first>>8) & 0xff); //prg-nr
396 capmt[11]=(unsigned char)(it->first & 0xff); //prg-nr
398 capmt[12]=it->second.front().version; //reserved - version - current/next
399 capmt[13]=0x00; //reserved - prg-info len
400 capmt[14]=0x00; //prg-info len
402 int lenpos=13;
403 int len=0;
404 int first=1;
405 int wp=15;
407 for( std::list<tempPMT_t>::iterator i = it->second.begin();
408 i != it->second.end(); ++i )
410 switch(i->type)
412 case 1: //PID
413 capmt[lenpos]=((len & 0xf00)>>8);
414 capmt[lenpos+1]=(len & 0xff);
415 len=0;
416 lenpos=wp+3;
417 first=1;
418 capmt[wp++]=(i->streamtype & 0xffff);
419 capmt[wp++]=((i->pid >> 8) & 0xff);
420 capmt[wp++]=(i->pid & 0xff);
421 wp+=2;
422 break;
423 case 2: //Descriptor
424 unsigned int x=0;
425 for(;x<caidcount;x++)
427 if(caids[x] == ((i->descriptor[2]<<8)|(i->descriptor[3])))
428 break;
431 if(x!=caidcount)
433 if(first)
435 first=0;
436 capmt[wp++]=0x01; //ca_pmt_command_id
437 len++;
440 memcpy(capmt+wp,i->descriptor,i->descriptor[1]+2);
441 wp+=i->descriptor[1]+2;
442 len+=i->descriptor[1]+2;
444 break;
448 capmt[lenpos]=((len & 0xf00)>>8);
449 capmt[lenpos+1]=(len & 0xff);
451 for(int i=1;i<MAX_SESSIONS;++i)
452 if(sessions[i].state && (sessions[i].service_class==0x30041 || sessions[i].service_class==0x34100))
454 // eDebug("[DVBCI] send capmt with session id %d", i);
455 capmt[3]=i; //session_id
456 create_sessionobject(capmt+4,capmt+9,wp-9,i);
457 #if 0
458 eDebug("CAPMT-LEN:%d",wp);
459 for(int i=0;i<wp;++i)
460 eDebugNoNewLine("%02x ",capmt[i]);
461 eDebug("");
462 #endif
467 void eDVBCI::create_sessionobject(unsigned char *tag,unsigned char *data,unsigned int len,int session)
469 unsigned char buffer[len+3+5+4]; //data + tag_len + max_lengtfieldlen + spdu_header
470 int newlen=len+3+4;
472 memcpy(buffer,"\x90\x2\x0\x3",4); //session nr.3 & capmt-tag
473 buffer[3]=session; //session_id
475 memcpy(buffer+4,tag,3);
477 if(len<128)
479 buffer[7]=len&0x7f;
480 memcpy(buffer+8,data,len);
481 newlen+=1;
483 else if(len>255)
485 buffer[7]=0x82;
486 buffer[8]=(len&0xff00)>>8;
487 buffer[9]=len&0xff;
488 memcpy(buffer+10,data,len);
489 newlen+=3;
491 else // len > 127
493 buffer[7]=0x81;
494 buffer[8]=len&0xff;
495 memcpy(buffer+9,data,len);
496 newlen+=2;
499 #if 0
500 for(int i=0;i<newlen;++i)
501 printf("%02x ",buffer[i]);
502 printf("\n");
503 #endif
504 sendTPDU(0xA0,newlen,1,buffer,true);
508 void eDVBCI::clearCAIDs()
510 eDVBServiceController *sapi=eDVB::getInstance()->getServiceAPI();
511 if(!sapi)
512 return;
514 sapi->clearCAlist();
516 caidcount=0;
519 void eDVBCI::addCAID(int caid)
521 caids[caidcount++]=caid & 0xffff;
524 void eDVBCI::pushCAIDs()
526 eDVBServiceController *sapi=eDVB::getInstance()->getServiceAPI();
527 if(!sapi)
528 return;
530 // eDebug("count for caids: %d",caidcount);
531 singleLock s(eDVBServiceController::availCALock);
532 for(unsigned int i=0;i<caidcount;++i)
533 sapi->availableCASystems.insert(caids[i]);
536 void eDVBCI::sendTPDU(unsigned char tpdu_tag,unsigned int len,unsigned char tc_id,unsigned char *data,bool dontQueue)
538 unsigned char *buffer = new unsigned char[len+7];
540 buffer[0]=tc_id;
541 buffer[1]=0;
542 buffer[2]=tpdu_tag;
544 if(len>127)
546 buffer[3]=0x82;
547 buffer[4]=((len+1)>>8);
548 buffer[5]=((len+1) & 0xff);
549 buffer[6]=tc_id;
550 memcpy(buffer+7,data,len);
552 /* for ( int i=0; i < len+5; ++i )
553 eDebugNoNewLine("%02x ", buffer[i+2] );
554 eDebug("");*/
556 if ( sendqueue.empty() )
558 // eDebug("queue empty.. try to send data");
560 if ( !sendData(tc_id,buffer+2,len+5) )
562 // eDebug("CI is busy... push to sendqueue..");
563 sendqueue.push( queueData(tc_id, buffer, len+5) );
565 else
566 delete [] buffer;
568 else // already data in sendqueue.. push to end of queue
570 // eDebug("queuesize = %d.. append new data to queue", sendqueue.size());
571 sendqueue.push( queueData(tc_id, buffer, len+5) );
574 else
576 buffer[3]=len+1;
577 buffer[4]=tc_id;
578 memcpy(buffer+5,data,len);
579 /* for ( int i=0; i < len+3; ++i )
580 eDebugNoNewLine("%02x ", buffer[i+2] );
581 eDebug("");*/
582 if ( sendqueue.empty() )
584 // eDebug("queue empty.. try to send data");
585 if ( !sendData(tc_id,buffer+2,len+3) )
587 // eDebug("CI is busy... push to sendqueue..");
588 sendqueue.push( queueData(tc_id, buffer, len+3) );
590 else
591 delete [] buffer;
593 else
595 // eDebug("queusize = %d.. append new data to queue", sendqueue.size());
596 sendqueue.push( queueData(tc_id, buffer, len+3) );
601 bool eDVBCI::sendData(unsigned char tc_id,unsigned char *data,unsigned int len)
603 stopTimer();
605 if(write(fd,data,len)<0)
607 if (errno == EBUSY)
608 return false;
609 eDebug("[DVBCI] write error");
610 ci_state=0;
611 dataAvailable(0);
614 return true;
617 void eDVBCI::help_manager(unsigned int session)
619 switch(sessions[session].internal_state)
621 case 0:
623 unsigned char buffer[12];
624 eDebug("[DVBCI] [HELP MANAGER] up to now nothing happens -> profile_enq");
626 memcpy(buffer,"\x90\x2\x0\x1\x9f\x80\x10\x0",8);
627 sendTPDU(0xA0,8,sessions[session].tc_id,buffer);
629 sessions[session].internal_state=1;
630 break;
632 case 1:
634 unsigned char buffer[12];
636 eDebug("[DVBCI] [HELP MANAGER] profile_change");
638 memcpy(buffer,"\x90\x2\x0\x1\x9f\x80\x12\x0",8);
639 sendTPDU(0xA0,8,sessions[session].tc_id,buffer);
641 sessions[session].internal_state=2;
642 break;
644 case 2:
646 unsigned char buffer[40];
648 eDebug("[DVBCI] [HELP MANAGER] profile_reply");
649 //was wir alles koennen :)
650 memcpy(buffer,"\x90\x2\x0\x1\x9f\x80\x11",7);
652 buffer[7]=0x10;
653 buffer[8]=0x00; //res. manager
654 buffer[9]=0x01;
655 buffer[10]=0x00;
656 buffer[11]=0x41; //? :)
658 buffer[12]=0x00;
659 buffer[13]=0x02; //02
660 buffer[14]=0x00;
661 buffer[15]=0x41; //CA
663 buffer[16]=0x00;
664 buffer[17]=0x03;
665 buffer[18]=0x00; //00 //date-time
666 buffer[19]=0x41;
667 buffer[20]=0x00;
668 buffer[21]=0x40;
669 buffer[22]=0x00; //mmi
670 buffer[23]=0x41;
672 sendTPDU(0xA0,24,sessions[session].tc_id,buffer);
673 sessions[session].internal_state=3;
674 break;
676 default:
677 //printf("[HELP MANAGER] undefined state\n"); //or ready ;)
678 break;
682 void eDVBCI::app_manager(unsigned int session)
684 switch(sessions[session].internal_state)
686 case 0:
688 unsigned char buffer[12];
689 eDebug("[DVBCI] [APPLICATION MANAGER] up to now nothing happens -> app_info_enq");
690 memcpy(buffer,"\x90\x2\x0\x2\x9f\x80\x20\x0",8);
691 sendTPDU(0xA0,8,sessions[session].tc_id,buffer);
692 sessions[session].internal_state=1;
693 break;
695 case 1:
696 break;
697 default:
698 break;
703 void eDVBCI::ca_manager(unsigned int session)
705 // eDebug("[DVBCI] ca_manager session %d", session );
706 switch(sessions[session].internal_state)
708 case 0:
710 unsigned char buffer[12];
711 sessions[session].internal_state=1;
714 /* // disabled.. for more info see dvbservice.cpp
715 eServiceHandler *serviceHandler =
716 eServiceInterface::getInstance()->getService();
717 if ( serviceHandler && serviceHandler->getFlags() & eServiceHandler::flagIsScrambled )*/
719 if ( ::ioctl(fd,CI_TS_ACTIVATE)<0 )
720 eDebug("CI_TS_ACTIVATE failed (%m)");
723 clearCAIDs();
724 eDebug("[DVBCI] [CA MANAGER] up to now nothing happens -> ca_info_enq");
726 memcpy(buffer,"\x90\x2\x0\x3\x9f\x80\x30\x0",8);
728 if(!sessions[session].state)
729 eDebug("CA-MANAGER SESSION %d not assigned !", session);
730 else
732 buffer[3]=session;
733 if ( sessions[session].service_class==0x30041 ||
734 sessions[session].service_class==0x34100 )
735 sendTPDU(0xA0,8,sessions[session].tc_id,buffer);
736 else
737 eDebug("CA-MANAGER SESSION %d has invalid service_class %08x", sessions[session].service_class );
739 break;
741 case 1:
743 eDebug("[DVBCI] [CA MANAGER] send ca_pmt");
744 //sendCAPMT();
745 versions.clear();
746 newService(); // send with "only" service
747 sessions[session].internal_state=2;
748 break;
750 default:
751 eDebug("unhandled session(%d) state %d", session, sessions[session].internal_state );
752 break;
756 void eDVBCI::handle_session(unsigned char *data,int len)
758 #if 0
759 eDebugNoNewLine("[DVBCI] dump handle session tag:");
760 for (int i=0; i < len; ++i )
761 eDebugNoNewLine("%02x ", data[i]);
762 eDebug("");
763 #endif
765 if(data[4]==0x9f && data[5]==0x80 && data[6]==0x11)
766 help_manager(data[3]);
767 else if(data[4]==0x9f && data[5]==0x80 && data[6]==0x10)
769 help_manager(data[3]);
770 ci_progress("help-manager init");
772 else if(data[4]==0x9f && data[5]==0x80 && data[6]==0x21)
774 eDebug("[DVBCI] APP-INFO");
775 memcpy(appName,data+14,data[13]);
776 appName[data[13]]=0x0;
777 ci_progress("application manager-init");
779 else if(data[4]==0x9f && data[5]==0x80 && data[6]==0x31)
781 int i;
782 eDebug("[DVBCI] CA-INFO");
784 if(data[7]>(len+8))
785 eDebug("[DVBCI] [CA MANAGER] error in ca-info");
787 ci_progress("[DVBCI]ca-manager init");
789 for(i=8;i<data[7]+8;i+=2)
791 eDebug("[DVBCI] [CA MANAGER] add CAID: %04x",data[i]<<8|data[i+1]);
792 addCAID(data[i]<<8|data[i+1]);
794 pushCAIDs();
796 if ( !sessions[data[3]].state )
797 eDebug("[DVBCI] SESSION %d is not assigned !");
798 else
800 if ( sessions[data[3]].service_class==0x30041 ||
801 sessions[data[3]].service_class==0x34100)
802 ca_manager(data[3]);
803 else
804 eDebug("SESSION ID %d is no CA-MANAGER");
807 else if(data[4]==0x9f && data[5]==0x88 && data[6]==0x01)
809 unsigned char buffer[20];
810 eDebug("[DVBCI] [APPLICATION MANAGER] -> display-control");
811 memcpy(buffer,"\x90\x2\x0\x4\x9f\x88\x2\x2\x1\x1",10);
812 buffer[3]=data[3]; // session id
813 sendTPDU(0xA0,10,1,buffer);
815 else if(data[4]==0x9f && data[5]==0x84 && data[6]==0x40)
817 unsigned char buffer[20];
818 eDebug("[DVBCI] [DATE TIME ENQ]");
819 memcpy(buffer,"\x90\x2\x0\x5\x9f\x88\x41\x5\xcd\x8A\x23\x13\x12",13);
820 buffer[3]=data[3]; // session id
821 sendTPDU(0xA0,13,1,buffer);
823 else if(data[4]==0x9f && data[5]==0x88)
825 char buffer[len-4];
826 eDebug("[DVBCI] [APPLICATION MANAGER] -> mmi_menu");
827 #if 0
828 eDebug("[DVBCI] mmi len:%d",len);
829 for(int i=0;i<len;++i)
830 eDebugNoNewLine("%02x ",data[i]);
831 eDebug("");
832 #endif
833 memcpy(buffer,data+4,len-4);
834 ci_mmi_progress(buffer,len-4);
836 else
838 eDebug("[DVBCI] unhandled session:");
839 for(int i=0;i<len;++i)
840 eDebugNoNewLine("%02x ",data[i]);
841 eDebug("");
845 int eDVBCI::service_available(unsigned long service_class)
847 switch(service_class)
849 case 0x010041:
850 case 0x020041:
852 case 0x030041:
853 case 0x034100: //WTF? find the bug ... endianess fool on integer-fields?
854 //if it is so...perhaps its better you switch the xa to 8bit mode *g*
855 case 0x400041:
856 case 0x240041:
857 return 1;
858 default:
859 eDebug("[DVBCI] service %08x not available", service_class);
860 return 0;
864 void eDVBCI::handle_spdu(unsigned int tpdu_tc_id,unsigned char *data,int len)
866 unsigned char buffer[40];
868 // eDebug("[DVBCI]handle_spdu(%02x)", data[0]);
870 switch(data[0])
872 case 0x90:
873 handle_session(data,len);
874 break;
875 case 0x91:
876 if(service_available(*(unsigned long*)(data+2)))
878 #if 0
879 eDebugNoNewLine("[DVBCI] dump open session tag:");
880 for (int i=0; i < len; ++i )
881 eDebugNoNewLine("%02x ", data[i]);
882 eDebug("");
883 #endif
884 int i=1;
885 for(;i<MAX_SESSIONS;++i)
886 if(sessions[i].state==STATE_FREE)
887 break;
888 if(i==MAX_SESSIONS)
890 eDebug("[DVBCI] no free sessions left");
891 memcpy(buffer,"\x92\x7\xf0\x0\x0\x0\x0\x0\x0",9);
892 memcpy(buffer+3,data+2,4);
893 sendTPDU(0xA0,9,tpdu_tc_id,buffer);
894 return;
897 sessions[i].state=STATE_OPEN;
898 sessions[i].service_class=*(unsigned long*)(data+2);
899 sessions[i].tc_id=tpdu_tc_id;
900 sessions[i].internal_state=0;
902 memcpy(buffer,"\x92\x7\x0",3);
903 memcpy(buffer+3,data+2,4);
904 buffer[7]=i>>8;
905 buffer[8]=i& 0xff;
906 sendTPDU(0xA0,9,tpdu_tc_id,buffer);
908 eDebug("[DVBCI] serviceclass (%x) request accepted on %d",*(unsigned long*)(data+2),i);
910 if(sessions[i].service_class==0x10041)
911 help_manager(i);
912 if(sessions[i].service_class==0x20041)
913 app_manager(i);
914 if(sessions[i].service_class==0x30041)
915 ca_manager(i);
916 if(sessions[i].service_class==0x34100)
917 ca_manager(i);
919 else
921 eDebug("[DVBCI] unknown serviceclass (%x) requested",*(unsigned long*)(data+2));
922 memcpy(buffer,"\x92\x7\xf0",3);
923 memcpy(buffer+3,data+2,4);
924 sendTPDU(0xA0,9,tpdu_tc_id,buffer);
926 break;
927 case 0x95: //T_close_session
929 #if 0
930 eDebugNoNewLine("[DVBCI] dump close session tag:");
931 for (int i=0; i < len; ++i )
932 eDebugNoNewLine("%02x ", data[i]);
933 eDebug("");
934 #endif
935 memcpy(buffer,"\x96\x3\xf0",3);
936 buffer[3]=data[2];
937 buffer[4]=data[3];
938 if( sessions[data[3]].state != STATE_FREE )
940 buffer[2]=0; // session freed
941 sessions[data[3]].state=STATE_FREE;
942 eDebug("[DVBCI] freeing session %d",data[3]);
943 if(sessions[data[3]].service_class == 0x400041)
945 eDebug("[DVBCI] close mmi after session free");
946 char *buf="\x9f\x88\x00\x00";
947 ci_mmi_progress(buf,4);
950 sendTPDU(0xA0,5,tpdu_tc_id,buffer);
951 break;
953 default:
954 eDebug("[DVBCI] unknown SPDU-TAG:%x",data[0]);
958 void eDVBCI::receiveTPDU(unsigned char tpdu_tag,unsigned int tpdu_len,unsigned char tpdu_tc_id,unsigned char *data)
960 // eDebug("[DVBCI] receiveTPDU %02x", tpdu_tag);
961 switch(tpdu_tag)
963 case 0x80:
964 //if(data[0]==0x80)
965 // sendTPDU(0x81,0,tpdu_tc_id,0);
966 //else
967 // startTimer();
968 break;
969 case 0x83:
970 eDebug("[DVBCI] T_C_ID %d wurde erstellt",tpdu_tc_id);
972 //startTimer();
973 break;
974 case 0xA0:
975 if(tpdu_len)
977 if(data[0] >= 0x90 && data[0] <= 0x96)
979 handle_spdu(tpdu_tc_id,data,tpdu_len);
980 //startTimer();
982 else
984 eDebug("[DVBCI] unknown spdu-tag:%x",data[0]);
987 break;
988 default:
989 eDebug("[DVBCI] unknown tpdu-tag:%x, len = %d", tpdu_tag, tpdu_len );
993 #if 0
994 void eDVBCI::incoming(unsigned char *buffer,int len)
996 int tc_id;
997 int m_l;
998 int tpdu_tag;
999 int tpdu_len;
1000 int tpdu_tc_id;
1001 int x=0;
1002 #if 0
1003 printf("incoming:");
1004 for(int i=0;i<len;++i)
1005 printf("%02x ",buffer[i]);
1006 printf("\n");
1007 #endif
1008 tc_id=buffer[x++];
1009 m_l=buffer[x++];
1011 if(buffer[0]!=0x1)
1012 return;
1014 if(!ml_bufferlen)
1015 if((buffer[2] & 0xF0) != 0x80 && (buffer[2] & 0xF0) != 0xA0)
1016 return;
1018 if(len<6)
1019 return;
1020 //the cheapest defrag on earth *g*
1021 if(m_l && ml_bufferlen==0) //first fragment
1023 int y;
1024 tpdu_tag=buffer[x++];
1025 tpdu_len=y=buffer[x++];
1026 if(y&0x80) //aua fix me
1028 //eDebug("y & 0x80 %x",tpdu_len);
1029 y&=0x7f;
1030 int i;
1031 for(i=0;i<y;++i)
1032 tpdu_len=(buffer[x++]&0xff)<<(((y*8)-8)-(i*8));
1033 //x++;
1034 //tpdu_len=buffer[x++];
1035 //eDebug("len:%d\n",tpdu_len);
1037 tpdu_len--;
1038 tpdu_tc_id=buffer[x++];
1040 memcpy(ml_buffer,buffer+x,len-7);
1041 ml_bufferlen=len-7;
1042 ml_buffersize=tpdu_len;
1043 dataAvailable(0);
1045 else if(!m_l && ml_bufferlen) //last fragment
1047 memcpy(ml_buffer+ml_bufferlen,buffer+2,len-2);
1048 receiveTPDU(0xA0,ml_buffersize,1,ml_buffer);
1049 ml_bufferlen=0;
1051 else //not fragmented
1053 while(x<len)
1055 int y;
1056 tpdu_tag=buffer[x++];
1057 tpdu_len=y=buffer[x++];
1058 if(y&0x80) //aua fix me
1060 //eDebug("y & 0x80 %x",tpdu_len);
1061 y&=0x7f;
1062 int i;
1063 for(i=0;i<y;++i)
1064 tpdu_len=(buffer[x++]&0xff)<<(((y*8)-8)-(i*8));
1065 //tpdu_len=buffer[x++];
1066 //eDebug("len:%d\n",tpdu_len);
1068 tpdu_len--;
1069 //if(tpdu_len>(len-6))
1070 // tpdu_len=len-6;
1071 tpdu_tc_id=buffer[x++];
1072 #if 0
1073 printf("tpdu (%02x):",tpdu_tag);
1074 for(int i=0;i<tpdu_len;++i)
1075 printf("%02x ",buffer[(x-tpdu_len+1)+i]);
1076 printf("\n");
1077 #endif
1078 receiveTPDU(tpdu_tag,tpdu_len,tpdu_tc_id,buffer+x);
1079 x+=tpdu_len;
1083 #else
1085 ptrlpduQueueElem eDVBCI::AllocLpduQueueElem(unsigned char t_c_id)
1087 ptrlpduQueueElem curElem;
1089 curElem = new lpduQueueElem;
1091 curElem->lpduLen = 0;
1093 (curElem->lpdu)[0] = t_c_id;
1095 curElem->nextElem = NULL;
1097 return curElem;
1100 int eDVBCI::lpduQueueElemIsMore(ptrlpduQueueElem curElem)
1101 // Check header of contained LPDU for "more" flag
1104 if ((curElem->lpdu)[1] & 0x80)
1105 return 1;
1106 else
1107 return 0;
1110 void eDVBCI::incoming(unsigned char *buffer,int len)
1112 ptrlpduQueueElem curElem, lastElem;
1114 unsigned char t_c_id;
1116 unsigned char * payloadData;
1117 long payloadIndex;
1118 long length;
1119 unsigned char from_t_c_id;
1121 payloadData = NULL;
1122 length = 0;
1123 from_t_c_id = 0;
1125 // Allocate LPDU queue element
1126 curElem = AllocLpduQueueElem(0);
1128 // Get LPDU
1129 memcpy(curElem->lpdu,buffer,len);
1130 curElem->lpduLen=len;
1132 // get transport ID
1133 t_c_id = (curElem->lpdu)[0];
1135 // Append to the current receive queue for the transport ID
1136 lastElem = lpduReceiveQueues[t_c_id].firstLPDU;
1138 if (lastElem == NULL)
1140 lpduReceiveQueues[t_c_id].firstLPDU = curElem;
1142 else
1144 while (lastElem->nextElem != NULL)
1145 lastElem = lastElem->nextElem;
1147 lastElem->nextElem = curElem;
1149 // Increment LPDU count
1150 lpduReceiveQueues[t_c_id].numLPDUS++;
1152 if (!lpduQueueElemIsMore(curElem))
1154 payloadIndex = 0;
1156 length = lpduReceiveQueues[t_c_id].numLPDUS * LPDUPAYLOADLEN;
1157 from_t_c_id = t_c_id;
1159 payloadData = new unsigned char[length];
1160 length = 0;
1162 curElem = lpduReceiveQueues[t_c_id].firstLPDU;
1164 while (curElem != NULL)
1166 memcpy(payloadData + payloadIndex, (curElem->lpdu) + LPDUHEADERLEN, (curElem->lpduLen) - LPDUHEADERLEN);
1168 payloadIndex += ((curElem->lpduLen) - LPDUHEADERLEN);
1169 (length) += ((curElem->lpduLen) - LPDUHEADERLEN);
1171 lastElem = curElem;
1172 curElem = curElem->nextElem;
1174 // And remove element
1175 delete lastElem;
1178 lpduReceiveQueues[t_c_id].numLPDUS = 0;
1179 lpduReceiveQueues[t_c_id].firstLPDU = NULL;
1181 //printf("data assembled\n");
1182 //for(int i=0;i<length;++i)
1183 // printf("%02x ",payloadData[i]);
1184 //printf("\n");
1186 //if(payloadData[length-4] != 0x80)
1187 // printf("Status-Field broken!!! (tag)\n");
1189 //if(payloadData[length-3] != 0x2)
1190 // printf("Status-Field broken!!! (len)\n");
1192 if(payloadData[length-1] == 0x80)
1194 // eDebug("[DVBCI] query data");
1195 sendTPDU(0x81,0,payloadData[length-2],0);
1198 length-=4;
1200 int cl=payloadData[1] & 0x7f;
1201 int lenfield=1;
1202 if(payloadData[1] & 0x80)
1204 lenfield = payloadData[1] & 0x7f;
1206 cl=0;
1207 for(int i=0;i<lenfield;++i)
1208 cl |= payloadData[2+i] << ((lenfield-(i+1))*8);
1210 lenfield++;
1211 //printf("lenfield:%d len:%d\n",lenfield,cl);
1214 //printf("tpdu\n");
1215 //for(int i=0;i<length;++i)
1216 // printf("%02x ",payloadData[i]);
1217 //printf("\n");
1219 if(length>1)
1220 receiveTPDU(payloadData[0],cl,t_c_id,payloadData+(2+lenfield));
1222 delete [] payloadData;
1224 //startTimer();
1227 #endif
1229 void eDVBCI::startTimer()
1231 pollTimer.start(80,true);
1234 void eDVBCI::stopTimer()
1236 pollTimer.stop();
1239 void eDVBCI::dataAvailable(int what)
1241 int present;
1242 unsigned char buffer[1024];
1243 int size;
1245 stopTimer();
1247 if ( what != 1000 )
1249 if (::ioctl(fd,CI_GET_STATUS,&present)<0)
1250 eDebug("[DVBCI] GET_STATUS failed (%m)");
1252 if(present == 2 || present != 1)
1254 eDebug("[DVBCI] module removed");
1256 // clear receive lpdu queues
1257 ptrlpduQueueElem curElem, lastElem;
1258 for (int i=0; i < MAXTRANSPORTSESSIONS; ++i)
1260 if (lpduReceiveQueues[i].numLPDUS)
1262 curElem = lpduReceiveQueues[i].firstLPDU;
1263 while (curElem != NULL)
1265 lastElem = curElem;
1266 curElem = curElem->nextElem;
1267 // And remove element
1268 delete lastElem;
1273 // clear sendqueue
1274 while(sendqueue.size())
1276 delete [] sendqueue.top().data;
1277 sendqueue.pop();
1280 strcpy(appName,_("no module"));
1281 ci_progress(appName);
1283 char *buf="\x9f\x88\x00\x00";
1284 ci_mmi_progress(buf,4);
1286 for(int i=1;i<MAX_SESSIONS;++i)
1287 sessions[i].state=STATE_FREE;
1289 ::read(fd,&buffer,0);
1290 ci_state=0;
1291 clearCAIDs();
1293 return;
1297 if(ci_state==0) //CI plugged
1299 int i;
1300 eDebug("[DVBCI] module inserted");
1302 ci_progress("module found");
1304 // eZapMain::getInstance()->postMessage(eZapMessage(1,"Common Interface","CI inserted - initializing...",10),0);
1305 // SEND FAKE Message to eZapMain... now we can show ci plug message
1306 char *buf="INIT";
1307 ci_mmi_progress(buf,4);
1309 for(i=1;i<MAX_SESSIONS;++i)
1310 sessions[i].state=STATE_FREE;
1312 ml_bufferlen=0;
1314 ::read(fd,&buffer,0);
1316 if (::ioctl(fd,CI_RESET)<0 ) // != 0
1318 eDebug("[DVBCI] RESET failed (%m)");
1319 ci_state=0;
1320 clearCAIDs();
1321 return;
1324 // clear sendqueue
1325 while ( sendqueue.size() )
1327 // eDebug("[DVBCI] clear queue");
1328 delete [] sendqueue.top().data;
1329 sendqueue.pop();
1332 ci_state=1;
1335 size=::read(fd,&buffer,sizeof(buffer));
1336 //eDebug("READ:%d",size);
1338 if(size>0)
1340 int i;
1341 #if 0
1342 for(i=0;i<size;++i)
1343 printf("%02x ",buffer[i]);
1344 printf("\n");
1345 #endif
1346 incoming(buffer,size);
1348 if ( sendqueue.size() )
1350 queueData d = sendqueue.top();
1351 sendqueue.pop();
1352 if ( !sendData( d.tc_id, d.data+2, d.len ) )
1354 // add this entry with higher priority to sendqueue..
1355 sendqueue.push( queueData( d.tc_id, d.data, d.len, 1 ) );
1357 else
1358 delete [] d.data;
1361 if (::ioctl(fd,8,&i)<0)
1362 eDebug("[DVBCI] GET failed (%m)");
1364 if(i==4)
1366 startTimer();
1368 else
1369 stopTimer();
1370 return;
1373 if(ci_state==1)
1375 sendTPDU(0x82,0,1,0);
1376 ci_state=2;
1380 void eDVBCI::poll()
1382 int present;
1384 stopTimer();
1386 #if 0
1387 eDebug("[DVBCI] TIMER");
1388 #endif
1390 if (::ioctl(fd,CI_GET_STATUS,&present)<0)
1391 eDebug("CI_GET_STATUS failed (%m)");
1393 if(present) //CI removed
1394 sendTPDU(0xA0,0,1,0);
1397 #endif