]> www.vanbest.org Git - sasc-ng.git/commitdiff
device/cam structural change (experimental)
authorleslie <unknown>
Mon, 8 Aug 2011 18:49:04 +0000 (20:49 +0200)
committerleslie <unknown>
Mon, 8 Aug 2011 18:49:04 +0000 (20:49 +0200)
42 files changed:
cam.c
cam.h
data.c
data.h
device.c
device.h
filter.c
filter.h
global.h [new file with mode: 0644]
override.c
po/de_DE.po
po/fi_FI.po
po/fr_FR.po
po/hu_HU.po
po/it_IT.po
po/lt_LT.po
po/nl_NL.po
po/pl_PL.po
po/ru_RU.po
po/sv_SE.po
sc.c
sc.h [deleted file]
smartcard.c
system.c
system.h
systems/cardclient/aroureos.c
systems/cardclient/camd.c
systems/cardclient/cc.c
systems/cardclient/cc.h
systems/cardclient/cccam.c
systems/cardclient/cccam2.c
systems/cardclient/gbox.c
systems/cardclient/newcamd.c
systems/cardclient/radegast.c
systems/irdeto/irdeto1.c
systems/nagra/nagra1.c
systems/shl/shl.c
systems/viaccess/tps.c
systems/viaccess/tps.h
systems/viaccess/viaccess.c
testing/filterhelper.c
version.h

diff --git a/cam.c b/cam.c
index 1e8a9c22905da2afc77e4a4d5b908e70fd8f26f3..0bc5c68d70ba66a363c36f59676ba98847723d3e 100644 (file)
--- a/cam.c
+++ b/cam.c
 #include <stdlib.h>
 #include <stdio.h>
 #include <errno.h>
+#include <sys/ioctl.h>
 
+#include <vdr/device.h>
 #include <vdr/channels.h>
 #include <vdr/thread.h>
+#include <vdr/ringbuffer.h>
 
 #include "cam.h"
+#include "global.h"
 #include "device.h"
 #include "scsetup.h"
 #include "filter.h"
@@ -33,6 +37,7 @@
 #include "override.h"
 #include "misc.h"
 #include "log-core.h"
+#include "FFdecsa/FFdecsa.h"
 
 #define IDLE_SLEEP          0 // idleTime when sleeping
 #define IDLE_GETCA        200 // idleTime when waiting for ca descriptors
@@ -155,26 +160,26 @@ void cLogStats::Action(void)
 // -- cHookManager -------------------------------------------------------------
 
 class cHookManager : public cAction {
-  int cardNum;
+  const char *devId;
   cSimpleList<cLogHook> hooks;
   //
-  cPidFilter *AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc);
+  cPidFilter *AddFilter(int Pid, int Section, int Mask, int IdleTime);
   void ClearHooks(void);
   void DelHook(cLogHook *hook);
 protected:
   virtual void Process(cPidFilter *filter, unsigned char *data, int len);
 public:
-  cHookManager(int CardNum);
+  cHookManager(cDevice *Device, const char *DevId);
   virtual ~cHookManager();
   void AddHook(cLogHook *hook);
   bool TriggerHook(int id);
   void Down(void);
   };
 
-cHookManager::cHookManager(int CardNum)
-:cAction("hookmanager",CardNum)
+cHookManager::cHookManager(cDevice *Device, const char *DevId)
+:cAction("hookmanager",Device,DevId)
 {
-  cardNum=CardNum;
+  devId=DevId;
   Priority(10);
 }
 
@@ -207,12 +212,11 @@ bool cHookManager::TriggerHook(int id)
 void cHookManager::AddHook(cLogHook *hook)
 {
   Lock();
-  PRINTF(L_CORE_HOOK,"%d: starting hook '%s' (%04x)",cardNum,hook->name,hook->id);
+  PRINTF(L_CORE_HOOK,"%s: starting hook '%s' (%04x)",devId,hook->name,hook->id);
   hook->delay.Set(CHAIN_HOLD);
-  hook->cardNum=cardNum;
   hooks.Add(hook);
   for(cPid *pid=hook->pids.First(); pid; pid=hook->pids.Next(pid)) {
-    cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,pid->mode,CHAIN_HOLD/8,false);
+    cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,CHAIN_HOLD/8);
     if(filter) {
       filter->userData=(void *)hook;
       pid->filter=filter;
@@ -223,7 +227,7 @@ void cHookManager::AddHook(cLogHook *hook)
 
 void cHookManager::DelHook(cLogHook *hook)
 {
-  PRINTF(L_CORE_HOOK,"%d: stopping hook '%s' (%04x)",cardNum,hook->name,hook->id);
+  PRINTF(L_CORE_HOOK,"%s: stopping hook '%s' (%04x)",devId,hook->name,hook->id);
   for(cPid *pid=hook->pids.First(); pid; pid=hook->pids.Next(pid)) {
     cPidFilter *filter=pid->filter;
     if(filter) {
@@ -234,15 +238,15 @@ void cHookManager::DelHook(cLogHook *hook)
   hooks.Del(hook);
 }
 
-cPidFilter *cHookManager::AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc)
+cPidFilter *cHookManager::AddFilter(int Pid, int Section, int Mask, int IdleTime)
 {
   cPidFilter *filter=NewFilter(IdleTime);
   if(filter) {
     filter->SetBuffSize(32768);
-    filter->Start(Pid,Section,Mask,Mode,Crc);
-    PRINTF(L_CORE_HOOK,"%d: added filter pid=0x%.4x sct=0x%.2x/0x%.2x/0x%.2x idle=%d crc=%d",cardNum,Pid,Section,Mask,Mode,IdleTime,Crc);
+    filter->Start(Pid,Section,Mask);
+    PRINTF(L_CORE_HOOK,"%s: added filter pid=0x%.4x sct=0x%.2x/0x%.2x idle=%d",devId,Pid,Section,Mask,IdleTime);
     }
-  else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for hookmanager %d",cardNum);
+  else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for hookmanager %s",devId);
   return filter;
 }
 
@@ -257,7 +261,7 @@ void cHookManager::Process(cPidFilter *filter, unsigned char *data, int len)
         if(hook->bailOut || hook->delay.TimedOut()) DelHook(hook);
         }
       }
-    else PRINTF(L_CORE_HOOK,"%d: incomplete section %d != %d",cardNum,len,SCT_LEN(data));
+    else PRINTF(L_CORE_HOOK,"%s: incomplete section %d != %d",devId,len,SCT_LEN(data));
     }
   else {
     cLogHook *hook=(cLogHook *)(filter->userData);
@@ -269,20 +273,22 @@ void cHookManager::Process(cPidFilter *filter, unsigned char *data, int len)
 
 class cLogChain : public cSimpleItem {
 public:
-  int cardNum, caid, source, transponder;
+  cCam *cam;
+  const char *devId;
+  int caid, source, transponder;
   bool softCSA, active, delayed;
   cTimeMs delay;
   cPids pids;
   cSimpleList<cSystem> systems;
   //
-  cLogChain(int CardNum, bool soft, int src, int tr);
+  cLogChain(cCam *Cam, const char *DevId, bool soft, int src, int tr);
   void Process(int pid, const unsigned char *data);
   bool Parse(const unsigned char *cat);
   };
 
-cLogChain::cLogChain(int CardNum, bool soft, int src, int tr)
+cLogChain::cLogChain(cCam *Cam, const char *DevId, bool soft, int src, int tr)
 {
-  cardNum=CardNum; softCSA=soft; source=src; transponder=tr;
+  cam=Cam; devId=DevId; softCSA=soft; source=src; transponder=tr;
   active=delayed=false;
 }
 
@@ -299,7 +305,7 @@ bool cLogChain::Parse(const unsigned char *cat)
   if(cat[0]==0x09) {
     caid=WORD(cat,2,0xFFFF);
     LBSTARTF(L_CORE_AU);
-    LBPUT("%d: chain caid %04x",cardNum,caid);
+    LBPUT("%s: chain caid %04x",devId,caid);
     cSystem *sys;
     if(systems.Count()>0) {
       LBPUT(" ++");
@@ -313,7 +319,7 @@ bool cLogChain::Parse(const unsigned char *cat)
         while((sys=cSystems::FindBySysId(caid,!softCSA,Pri))) {
           Pri=sys->Pri();
           if(sys->HasLogger()) {
-            sys->CardNum(cardNum);
+            sys->SetOwner(cam);
             sys->ParseCAT(&pids,cat,source,transponder);
             systems.Add(sys);
             LBPUT(" %s(%d)",sys->Name(),sys->Pri());
@@ -325,7 +331,7 @@ bool cLogChain::Parse(const unsigned char *cat)
       }
     if(systems.Count()==0) LBPUT(" none available");
     for(cPid *pid=pids.First(); pid; pid=pids.Next(pid))
-       LBPUT(" [%04x-%02x/%02x/%02x]",pid->pid,pid->sct,pid->mask,pid->mode);
+       LBPUT(" [%04x-%02x/%02x]",pid->pid,pid->sct,pid->mask);
     LBEND();
     if(systems.Count()>0 && pids.Count()>0)
       return true;
@@ -337,7 +343,8 @@ bool cLogChain::Parse(const unsigned char *cat)
 
 class cLogger : public cAction {
 private:
-  int cardNum;
+  cCam *cam;
+  const char *devId;
   bool softCSA, up;
   cSimpleList<cLogChain> chains;
   cSimpleList<cEcmInfo> active;
@@ -350,7 +357,7 @@ private:
   ePreMode prescan;
   cTimeMs pretime;
   //
-  cPidFilter *AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc);
+  cPidFilter *AddFilter(int Pid, int Section, int Mask, int IdleTime);
   void SetChains(void);
   void ClearChains(void);
   void StartChain(cLogChain *chain);
@@ -359,7 +366,7 @@ private:
 protected:
   virtual void Process(cPidFilter *filter, unsigned char *data, int len);
 public:
-  cLogger(int CardNum, bool soft);
+  cLogger(cCam *Cam, cDevice *Device, const char *DevId, bool soft);
   virtual ~cLogger();
   void EcmStatus(const cEcmInfo *ecm, bool on);
   void Up(void);
@@ -367,10 +374,10 @@ public:
   void PreScan(int src, int tr);
   };
 
-cLogger::cLogger(int CardNum, bool soft)
-:cAction("logger",CardNum)
+cLogger::cLogger(cCam *Cam, cDevice *Device, const char *DevId, bool soft)
+:cAction("logger",Device,DevId)
 {
-  cardNum=CardNum; softCSA=soft;
+  cam=Cam; devId=DevId; softCSA=soft;
   catfilt=0; up=false; prescan=pmNone;
   Priority(10);
 }
@@ -384,9 +391,9 @@ void cLogger::Up(void)
 {
   Lock();
   if(!up) {
-    PRINTF(L_CORE_AUEXTRA,"%d: UP",cardNum);
+    PRINTF(L_CORE_AUEXTRA,"%s: UP",devId);
     catVers=-1;
-    catfilt=AddFilter(1,0x01,0xFF,0,0,true);
+    catfilt=AddFilter(1,0x01,0xFF,0);
     up=true;
     }
   Unlock();
@@ -396,7 +403,7 @@ void cLogger::Down(void)
 {
   Lock();
   if(up) {
-    PRINTF(L_CORE_AUEXTRA,"%d: DOWN",cardNum);
+    PRINTF(L_CORE_AUEXTRA,"%s: DOWN",devId);
     ClearChains();
     DelAllFilter();
     catfilt=0; up=false; prescan=pmNone;
@@ -415,7 +422,7 @@ void cLogger::PreScan(int src, int tr)
 void cLogger::EcmStatus(const cEcmInfo *ecm, bool on)
 {
   Lock();
-  PRINTF(L_CORE_AUEXTRA,"%d: ecm prgid=%d caid=%04x prov=%.4x %s",cardNum,ecm->prgId,ecm->caId,ecm->provId,on ? "active":"inactive");
+  PRINTF(L_CORE_AUEXTRA,"%s: ecm prgid=%d caid=%04x prov=%.4x %s",devId,ecm->prgId,ecm->caId,ecm->provId,on ? "active":"inactive");
   source=ecm->source; transponder=ecm->transponder;
   cEcmInfo *e;
   if(on) {
@@ -462,13 +469,13 @@ void cLogger::ClearChains(void)
 void cLogger::StartChain(cLogChain *chain)
 {
   if(chain->delayed)
-    PRINTF(L_CORE_AUEXTRA,"%d: restarting delayed chain %04x",cardNum,chain->caid);
+    PRINTF(L_CORE_AUEXTRA,"%s: restarting delayed chain %04x",devId,chain->caid);
   chain->delayed=false;
   if(!chain->active) {
-    PRINTF(L_CORE_AU,"%d: starting chain %04x",cardNum,chain->caid);
+    PRINTF(L_CORE_AU,"%s: starting chain %04x",devId,chain->caid);
     chain->active=true;
     for(cPid *pid=chain->pids.First(); pid; pid=chain->pids.Next(pid)) {
-      cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,pid->mode,CHAIN_HOLD/8,false);
+      cPidFilter *filter=AddFilter(pid->pid,pid->sct,pid->mask,CHAIN_HOLD/8);
       if(filter) {
         filter->userData=(void *)chain;
         pid->filter=filter;
@@ -481,7 +488,7 @@ void cLogger::StopChain(cLogChain *chain, bool force)
 {
   if(chain->active) {
     if(force || (chain->delayed && chain->delay.TimedOut())) {
-      PRINTF(L_CORE_AU,"%d: stopping chain %04x",cardNum,chain->caid);
+      PRINTF(L_CORE_AU,"%s: stopping chain %04x",devId,chain->caid);
       chain->active=false;
       for(cPid *pid=chain->pids.First(); pid; pid=chain->pids.Next(pid)) {
         cPidFilter *filter=pid->filter;
@@ -492,22 +499,22 @@ void cLogger::StopChain(cLogChain *chain, bool force)
         }
       }
     else if(!chain->delayed) {
-      PRINTF(L_CORE_AUEXTRA,"%d: delaying chain %04x",cardNum,chain->caid);
+      PRINTF(L_CORE_AUEXTRA,"%s: delaying chain %04x",devId,chain->caid);
       chain->delayed=true;
       chain->delay.Set(CHAIN_HOLD);
       }
     }
 }
 
-cPidFilter *cLogger::AddFilter(int Pid, int Section, int Mask, int Mode, int IdleTime, bool Crc)
+cPidFilter *cLogger::AddFilter(int Pid, int Section, int Mask, int IdleTime)
 {
   cPidFilter *filter=NewFilter(IdleTime);
   if(filter) {
     if(Pid>1) filter->SetBuffSize(KILOBYTE(64));
-    filter->Start(Pid,Section,Mask,Mode,Crc);
-    PRINTF(L_CORE_AUEXTRA,"%d: added filter pid=0x%.4x sct=0x%.2x/0x%.2x/0x%.2x idle=%d crc=%d",cardNum,Pid,Section,Mask,Mode,IdleTime,Crc);
+    filter->Start(Pid,Section,Mask);
+    PRINTF(L_CORE_AUEXTRA,"%s: added filter pid=0x%.4x sct=0x%.2x/0x%.2x idle=%d",devId,Pid,Section,Mask,IdleTime);
     }
-  else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for logger %d",cardNum);
+  else PRINTF(L_GEN_ERROR,"no free slot or filter failed to open for logger %s",devId);
   return filter;
 }
 
@@ -522,7 +529,7 @@ void cLogger::ProcessCat(unsigned char *data, int len)
       if(chain)
         chain->Parse(&data[i]);
       else {
-        chain=new cLogChain(cardNum,softCSA,source,transponder);
+        chain=new cLogChain(cam,devId,softCSA,source,transponder);
         if(chain->Parse(&data[i]))
           chains.Add(chain);
         else
@@ -538,7 +545,7 @@ void cLogger::Process(cPidFilter *filter, unsigned char *data, int len)
     if(filter==catfilt) {
       int vers=(data[5]&0x3E)>>1;
       if(data[0]==0x01 && vers!=catVers) {
-        PRINTF(L_CORE_AUEXTRA,"%d: got CAT version %02x",cardNum,vers);
+        PRINTF(L_CORE_AUEXTRA,"%s: got CAT version %02x",devId,vers);
         catVers=vers;
         HEXDUMP(L_HEX_CAT,data,len,"CAT vers %02x",catVers);
         ClearChains();
@@ -563,7 +570,7 @@ void cLogger::Process(cPidFilter *filter, unsigned char *data, int len)
           if(chain->delayed) StopChain(chain,false);
           }
         }
-      else PRINTF(L_CORE_AU,"%d: incomplete section %d != %d",cardNum,len,SCT_LEN(data));
+      else PRINTF(L_CORE_AU,"%s: incomplete section %d != %d",devId,len,SCT_LEN(data));
       }
     }
   else {
@@ -714,6 +721,197 @@ bool cEcmCache::ParseLinePlain(const char *line)
   return true;
 }
 
+// -- cCaDescr -----------------------------------------------------------------
+
+class cCaDescr {
+private:
+  unsigned char *descr;
+  int len;
+public:
+  cCaDescr(void);
+  cCaDescr(const cCaDescr &arg);
+  ~cCaDescr();
+  const unsigned char *Get(int &l) const;
+  void Set(const cCaDescr *d);
+  void Set(const unsigned char *de, int l);
+  void Clear(void);
+  bool operator== (const cCaDescr &arg) const;
+  void Join(const cCaDescr *cd, bool rev=false);
+  cString ToString(void);
+  };
+
+cCaDescr::cCaDescr(void)
+{
+  descr=0; len=0;
+}
+
+cCaDescr::cCaDescr(const cCaDescr &cd)
+{
+  descr=0; len=0;
+  Set(cd.descr,cd.len);
+}
+
+cCaDescr::~cCaDescr()
+{
+  Clear();
+}
+
+const unsigned char *cCaDescr::Get(int &l) const
+{
+  l=len;
+  return descr;
+}
+
+void cCaDescr::Set(const cCaDescr *d)
+{
+  Set(d->descr,d->len);
+}
+
+void cCaDescr::Set(const unsigned char *de, int l)
+{
+  Clear();
+  if(l) {
+    descr=MALLOC(unsigned char,l);
+    if(descr) {
+      memcpy(descr,de,l);
+      len=l;
+      }
+    }
+}
+
+void cCaDescr::Clear(void)
+{
+  free(descr); descr=0; len=0;
+}
+
+void cCaDescr::Join(const cCaDescr *cd, bool rev)
+{
+  if(cd->descr) {
+    int l=len+cd->len;
+    unsigned char *m=MALLOC(unsigned char,l);
+    if(m) {
+      if(!rev) {
+        if(descr) memcpy(m,descr,len);
+        memcpy(m+len,cd->descr,cd->len);
+        }
+      else {
+        memcpy(m,cd->descr,cd->len);
+        if(descr) memcpy(m+cd->len,descr,len);
+        }
+      Clear();
+      descr=m; len=l;
+      }
+    }
+}
+
+bool cCaDescr::operator== (const cCaDescr &cd) const
+{
+  return len==cd.len && (len==0 || memcmp(descr,cd.descr,len)==0);
+}
+
+cString cCaDescr::ToString(void)
+{
+  if(!descr) return "<empty>";
+  char *str=AUTOARRAY(char,len*3+8);
+  int q=sprintf(str,"%02X",descr[0]);
+  for(int i=1; i<len; i++) q+=sprintf(str+q," %02X",descr[i]);
+  return str;
+}
+
+// -- cPrgPid ------------------------------------------------------------------
+
+class cPrgPid : public cSimpleItem {
+private:
+  bool proc;
+public:
+  int type, pid;
+  cCaDescr caDescr;
+  //
+  cPrgPid(int Type, int Pid) { type=Type; pid=Pid; proc=false; }
+  bool Proc(void) const { return proc; }
+  void Proc(bool is) { proc=is; };
+  };
+
+// -- cPrg ---------------------------------------------------------------------
+
+class cPrg : public cSimpleItem {
+private:
+  bool isUpdate, pidCaDescr;
+  //
+  void Setup(void);
+public:
+  int sid, source, transponder;
+  cSimpleList<cPrgPid> pids;
+  cCaDescr caDescr;
+  //
+  cPrg(void);
+  cPrg(int Sid, bool IsUpdate);
+  bool IsUpdate(void) const { return isUpdate; }
+  bool HasPidCaDescr(void) const { return pidCaDescr; }
+  void SetPidCaDescr(bool val) { pidCaDescr=val; }
+  bool SimplifyCaDescr(void);
+  void DumpCaDescr(int c);
+  };
+
+cPrg::cPrg(void)
+{
+  Setup();
+}
+
+cPrg::cPrg(int Sid, bool IsUpdate)
+{
+  Setup();
+  sid=Sid; isUpdate=IsUpdate;
+}
+
+void cPrg::Setup(void)
+{
+  sid=-1; source=-1; transponder=-1;
+  isUpdate=pidCaDescr=false;
+}
+
+void cPrg::DumpCaDescr(int c)
+{
+  PRINTF(c,"prgca: %s",*caDescr.ToString());
+  for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
+    PRINTF(c,"pidca %04x: %s",pid->pid,*pid->caDescr.ToString());
+}
+
+bool cPrg::SimplifyCaDescr(void)
+{
+//XXX
+PRINTF(L_CORE_PIDS,"SimplyCa entry pidCa=%d",HasPidCaDescr());
+DumpCaDescr(L_CORE_PIDS);
+//XXX
+
+  if(HasPidCaDescr()) {
+    bool equal=true;
+    if(pids.Count()>1) {
+      cPrgPid *pid0=pids.First();
+      for(cPrgPid *pid1=pids.Next(pid0); pid1; pid1=pids.Next(pid1))
+        if(!(pid0->caDescr==pid1->caDescr)) { equal=false; break; }
+      }
+    if(equal) {
+      cPrgPid *pid=pids.First();
+      caDescr.Join(&pid->caDescr);
+      for(; pid; pid=pids.Next(pid)) pid->caDescr.Clear();
+      SetPidCaDescr(false);
+      }
+    }
+  if(HasPidCaDescr()) {
+    for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
+      pid->caDescr.Join(&caDescr,true);
+    caDescr.Clear();
+    }
+
+//XXX
+PRINTF(L_CORE_PIDS,"SimplyCa exit pidCa=%d",HasPidCaDescr());
+DumpCaDescr(L_CORE_PIDS);
+//XXX
+
+  return HasPidCaDescr();
+}
+
 // -- cEcmPri ------------------------------------------------------------------
 
 class cEcmPri : public cSimpleItem {
@@ -726,7 +924,8 @@ public:
 
 class cEcmHandler : public cSimpleItem, public cAction {
 private:
-  int cardNum, cwIndex;
+  const char *devId;
+  int cwIndex;
   cCam *cam;
   char *id;
   cTimeMs idleTime;
@@ -767,7 +966,7 @@ private:
 protected:
   virtual void Process(cPidFilter *filter, unsigned char *data, int len);
 public:
-  cEcmHandler(cCam *Cam, int CardNum, int cwindex);
+  cEcmHandler(cCam *Cam, cDevice *Device, const char *DevId, int cwindex);
   virtual ~cEcmHandler();
   void Stop(void);
   void SetPrg(cPrg *Prg);
@@ -780,17 +979,17 @@ public:
   const char *Id(void) const { return id; }
   };
 
-cEcmHandler::cEcmHandler(cCam *Cam, int CardNum, int cwindex)
-:cAction("ecmhandler",CardNum)
+cEcmHandler::cEcmHandler(cCam *Cam, cDevice *Device, const char *DevId, int cwindex)
+:cAction("ecmhandler",Device,DevId)
 ,failed(32,0)
 {
   cam=Cam;
-  cardNum=CardNum;
+  devId=DevId;
   cwIndex=cwindex;
   sys=0; filter=0; ecm=0; ecmPri=0; mode=-1;
   trigger=ecmUpd=false; triggerMode=-1;
   filterSource=filterTransponder=0; filterCwIndex=-1; filterSid=-1;
-  id=bprintf("%d.%d",cardNum,cwindex);
+  id=bprintf("%s.%d",devId,cwindex);
 }
 
 cEcmHandler::~cEcmHandler()
@@ -835,7 +1034,7 @@ void cEcmHandler::ShiftCwIndex(int cwindex)
   if(cwIndex!=cwindex) {
     PRINTF(L_CORE_PIDS,"%s: shifting cwIndex from %d to %d",id,cwIndex,cwindex);
     free(id);
-    id=bprintf("%d.%d",cardNum,cwindex);
+    id=bprintf("%s.%d",devId,cwindex);
     dataMutex.Lock();
     trigger=true;
     cwIndex=cwindex;
@@ -1218,7 +1417,7 @@ cEcmInfo *cEcmHandler::JumpEcm(void)
     if(ecmPri->ecm!=ecm) {
       StopEcm();
       ecm=ecmPri->ecm;
-      filter->Start(ecm->ecm_pid,ecm->ecm_table,0xfe,0,false);
+      filter->Start(ecm->ecm_pid,ecm->ecm_table,0xfe);
       cam->LogEcmStatus(ecm,true);
       }
     else {
@@ -1230,7 +1429,8 @@ cEcmInfo *cEcmHandler::JumpEcm(void)
       if(dolog) PRINTF(L_GEN_DEBUG,"internal: handler %s, no system found for ident %04x (caid %04x pri %d)",id,ecmPri->sysIdent,ecmPri->ecm->caId,ecmPri->pri);
       return JumpEcm();
       }
-    sys->DoLog(dolog!=0); sys->CardNum(cardNum);
+    sys->DoLog(dolog!=0);
+    sys->SetOwner(cam);
     failed.SetMaxFail(sys->MaxEcmTry());
 
     if(dolog) PRINTF(L_CORE_ECM,"%s: try system %s (%04x) id %04x with ecm %x%s (pri=%d)",
@@ -1289,6 +1489,7 @@ void cEcmHandler::ParseCAInfo(int SysId)
             while((n=ecms.First())) {
               ecms.Del(n,false);
               n->SetSource(filterSid,filterSource,filterTransponder);
+              n->SetDvb(cam->Adapter(),cam->Frontend());
               n->AddCaDescr(&buff[index],buff[index+1]+2);
               overrides.UpdateEcm(n,dolog);
               LBSTARTF(L_CORE_ECM);
@@ -1330,38 +1531,803 @@ void cEcmHandler::ParseCAInfo(int SysId)
   PRINTF(L_CORE_ECMPROC,"%s: ecmPri list end",id);
 }
 
-// -- cCam ---------------------------------------------------------------
+// --- cChannelCaids -----------------------------------------------------------
+
+#ifndef SASC
+
+class cChannelCaids : public cSimpleItem {
+private:
+  int prg, source, transponder;
+  int numcaids;
+  caid_t caids[MAX_CI_SLOT_CAIDS+1];
+public:
+  cChannelCaids(cChannel *channel);
+  bool IsChannel(cChannel *channel);
+  void Sort(void);
+  void Del(caid_t caid);
+  bool HasCaid(caid_t caid);
+  bool Same(cChannelCaids *ch, bool full);
+  void HistAdd(unsigned short *hist);
+  void Dump(const char *devId);
+  const caid_t *Caids(void) { caids[numcaids]=0; return caids; }
+  int NumCaids(void) { return numcaids; }
+  int Source(void) const { return source; }
+  int Transponder(void) const { return transponder; }
+  };
+
+cChannelCaids::cChannelCaids(cChannel *channel)
+{
+  prg=channel->Sid(); source=channel->Source(); transponder=channel->Transponder();
+  numcaids=0;
+  for(const caid_t *ids=channel->Caids(); *ids; ids++)
+    if(numcaids<MAX_CI_SLOT_CAIDS) caids[numcaids++]=*ids;
+  Sort();
+}
+
+bool cChannelCaids::IsChannel(cChannel *channel)
+{
+  return prg==channel->Sid() && source==channel->Source() && transponder==channel->Transponder();
+}
+
+void cChannelCaids::Sort(void)
+{
+  caid_t tmp[MAX_CI_SLOT_CAIDS];
+  int c=0xFFFF;
+  for(int i=0; i<numcaids; i++) {
+    int d=0;
+    for(int j=0; j<numcaids; j++) if(caids[j]>d && caids[j]<c) d=caids[j];
+    tmp[i]=d; c=d;
+    }
+  memcpy(caids,tmp,sizeof(caids));
+}
+
+void cChannelCaids::Del(caid_t caid)
+{
+  for(int i=0; i<numcaids; i++)
+    if(caids[i]==caid) {
+      numcaids--; caids[i]=caids[numcaids];
+      if(numcaids>0) Sort();
+      caids[numcaids]=0;
+      break;
+      }
+}
+
+bool cChannelCaids::HasCaid(caid_t caid)
+{
+  for(int i=0; i<numcaids; i++) if(caids[i]==caid) return true;
+  return false;
+}
+
+bool cChannelCaids::Same(cChannelCaids *ch, bool full)
+{
+  if(full && (source!=ch->source || transponder!=ch->transponder)) return false;
+  if(numcaids!=ch->numcaids) return false;
+  return memcmp(caids,ch->caids,numcaids*sizeof(caid_t))==0;
+}
+
+void cChannelCaids::HistAdd(unsigned short *hist)
+{
+  for(int i=numcaids-1; i>=0; i--) hist[caids[i]]++;
+}
+
+void cChannelCaids::Dump(const char *devId)
+{
+  LBSTART(L_CORE_CAIDS);
+  LBPUT("%s: channel %d/%x/%x",devId,prg,source,transponder);
+  for(const caid_t *ids=Caids(); *ids; ids++) LBPUT(" %04x",*ids);
+  LBEND();
+}
+
+// --- cChannelList ------------------------------------------------------------
+
+class cChannelList : public cSimpleList<cChannelCaids> {
+private:
+  const char *devId;
+public:
+  cChannelList(const char *DevId);
+  void Unique(bool full);
+  void CheckIgnore(void);
+  int Histo(void);
+  void Purge(int caid, bool fullch);
+  };
+
+cChannelList::cChannelList(const char *DevId)
+{
+  devId=DevId;
+}
+
+void cChannelList::CheckIgnore(void)
+{
+  char *cache=MALLOC(char,0x10000);
+  if(!cache) return;
+  memset(cache,0,sizeof(char)*0x10000);
+  int cTotal=0, cHits=0;
+  for(cChannelCaids *ch=First(); ch; ch=Next(ch)) {
+    const caid_t *ids=ch->Caids();
+    while(*ids) {
+      int pri=0;
+      if(overrides.Ignore(ch->Source(),ch->Transponder(),*ids))
+        ch->Del(*ids);
+      else {
+        char c=cache[*ids];
+        if(c==0) cache[*ids]=c=(cSystems::FindIdentBySysId(*ids,false,pri) ? 1 : -1);
+        else cHits++;
+        cTotal++;
+        if(c<0) {
+          for(cChannelCaids *ch2=Next(ch); ch2; ch2=Next(ch2)) ch2->Del(*ids);
+          ch->Del(*ids);
+          }
+        else ids++;
+        }
+      }
+    }
+  free(cache);
+  PRINTF(L_CORE_CAIDS,"%s: after check",devId);
+  for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId);
+  PRINTF(L_CORE_CAIDS,"%s: check cache usage: %d requests, %d hits, %d%% hits",devId,cTotal,cHits,(cTotal>0)?(cHits*100/cTotal):0);
+}
+
+void cChannelList::Unique(bool full)
+{
+  for(cChannelCaids *ch1=First(); ch1; ch1=Next(ch1)) {
+    for(cChannelCaids *ch2=Next(ch1); ch2;) {
+      if(ch1->Same(ch2,full) || ch2->NumCaids()<1) {
+        cChannelCaids *t=Next(ch2);
+        Del(ch2);
+        ch2=t;
+        }
+      else ch2=Next(ch2);
+      }
+    }
+  if(Count()==1 && First() && First()->NumCaids()<1) Del(First());
+  PRINTF(L_CORE_CAIDS,"%s: after unique (%d)",devId,full);
+  for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId);
+}
+
+int cChannelList::Histo(void)
+{
+  int h=-1;
+  unsigned short *hist=MALLOC(unsigned short,0x10000);
+  if(hist) {
+    memset(hist,0,sizeof(unsigned short)*0x10000);
+    for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->HistAdd(hist);
+    int c=0;
+    for(int i=0; i<0x10000; i++)
+      if(hist[i]>c) { h=i; c=hist[i]; }
+    free(hist);
+    }
+  else PRINTF(L_GEN_ERROR,"malloc failed in cChannelList::Histo");
+  return h;
+}
+
+void cChannelList::Purge(int caid, bool fullch)
+{
+  for(cChannelCaids *ch=First(); ch;) {
+    if(!fullch) ch->Del(caid);
+    if(ch->NumCaids()<=0 || (fullch && ch->HasCaid(caid))) {
+      cChannelCaids *t=Next(ch);
+      Del(ch);
+      ch=t;
+      }
+    else ch=Next(ch);
+    }
+  if(Count()>0) {
+    PRINTF(L_CORE_CAIDS,"%s: still left",devId);
+    for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(devId);
+    }
+}
+
+// -- cCiFrame -----------------------------------------------------------------
+
+#define LEN_OFF 2
+
+cCiFrame::cCiFrame(void)
+{
+  rb=0; mem=0; len=alen=glen=0;
+}
+
+cCiFrame::~cCiFrame()
+{
+  free(mem);
+}
+
+unsigned char *cCiFrame::GetBuff(int l)
+{
+  if(!mem || l>alen) {
+    free(mem); mem=0; alen=0;
+    mem=MALLOC(unsigned char,l+LEN_OFF);
+    if(mem) alen=l;
+    }
+  len=l;
+  if(!mem) {
+    PRINTF(L_GEN_DEBUG,"internal: ci-frame alloc failed");
+    return 0;
+    }
+  return mem+LEN_OFF;
+}
+
+void cCiFrame::Put(void)
+{
+  if(rb && mem) {
+    *((short *)mem)=len;
+    rb->Put(mem,len+LEN_OFF);
+    }
+}
+
+unsigned char *cCiFrame::Get(int &l)
+{
+  if(rb) {
+    int c;
+    unsigned char *data=rb->Get(c);
+    if(data) {
+      if(c>LEN_OFF) {
+        int s=*((short *)data);
+        if(c>=s+LEN_OFF) {
+          l=glen=s;
+          return data+LEN_OFF;
+          }
+        }
+      LDUMP(L_GEN_DEBUG,data,c,"internal: ci rb frame sync got=%d avail=%d -",c,rb->Available());
+      rb->Clear();
+      }
+    }
+  return 0;
+}
+
+int cCiFrame::Avail(void)
+{
+  return rb ? rb->Available() : 0;
+}
+
+void cCiFrame::Del(void)
+{
+  if(rb && glen) {
+    rb->Del(glen+LEN_OFF);
+    glen=0;
+    }
+}
+
+// -- cScCamSlot ---------------------------------------------------------------
+
+#define TDPU_SIZE_INDICATOR 0x80
+
+#define CAID_TIME       300000 // time between caid scans
+#define TRIGGER_TIME     10000 // min. time between caid scan trigger
+#define SLOT_CAID_CHECK  10000
+#define SLOT_RESET_TIME    600
+
+class cScCamSlot : public cCamSlot {
+private:
+  cCam *cam;
+  unsigned short caids[MAX_CI_SLOT_CAIDS+1];
+  int slot, version;
+  const char *devId;
+  cTimeMs checkTimer;
+  bool reset, doReply;
+  cTimeMs resetTimer;
+  eModuleStatus lastStatus;
+  cRingBufferLinear rb;
+  cCiFrame frame;
+  //
+  int GetLength(const unsigned char * &data);
+  int LengthSize(int n);
+  void SetSize(int n, unsigned char * &p);
+  void CaInfo(int tcid, int cid);
+  bool Check(void);
+public:
+  cScCamSlot(cCam *Cam, const char *DevId, int Slot);
+  void Process(const unsigned char *data, int len);
+  eModuleStatus Status(void);
+  bool Reset(bool log=true);
+  cCiFrame *Frame(void) { return &frame; }
+  };
+
+cScCamSlot::cScCamSlot(cCam *Cam, const char *DevId, int Slot)
+:cCamSlot(Cam)
+,checkTimer(-SLOT_CAID_CHECK-1000)
+,rb(KILOBYTE(4),5+LEN_OFF,false,"SC-CI slot answer")
+{
+  cam=Cam; devId=DevId; slot=Slot;
+  version=0; caids[0]=0; doReply=false; lastStatus=msReset;
+  frame.SetRb(&rb);
+  Reset(false);
+}
+
+eModuleStatus cScCamSlot::Status(void)
+{
+  eModuleStatus status;
+  if(reset) {
+    status=msReset;
+    if(resetTimer.TimedOut()) reset=false;
+    }
+  else if(caids[0]) status=msReady;
+  else {
+    status=msPresent; //msNone;
+    Check();
+    }
+  if(status!=lastStatus) {
+    static const char *stext[] = { "none","reset","present","ready" };
+    PRINTF(L_CORE_CI,"%s.%d: status '%s'",devId,slot,stext[status]);
+    lastStatus=status;
+    }
+  return status;
+}
+
+bool cScCamSlot::Reset(bool log)
+{
+  reset=true; resetTimer.Set(SLOT_RESET_TIME);
+  rb.Clear();
+  if(log) PRINTF(L_CORE_CI,"%s.%d: reset",devId,slot);
+  return true;
+}
+
+bool cScCamSlot::Check(void)
+{
+  bool res=false;
+  bool dr=cam->IsSoftCSA(false) || ScSetup.ConcurrentFF>0;
+  if(dr!=doReply && !IsDecrypting()) {
+    PRINTF(L_CORE_CI,"%s.%d: doReply changed, reset triggered",devId,slot);
+    Reset(false);
+    doReply=dr;
+    }
+  if(checkTimer.TimedOut()) {
+    if(version!=cam->GetCaids(slot,0,0)) {
+      version=cam->GetCaids(slot,caids,MAX_CI_SLOT_CAIDS);
+      PRINTF(L_CORE_CI,"%s.%d: now using CAIDs version %d",devId,slot,version);
+      res=true;
+      }
+    checkTimer.Set(SLOT_CAID_CHECK);
+    }
+  return res;
+}
+
+int cScCamSlot::GetLength(const unsigned char * &data)
+{
+  int len=*data++;
+  if(len&TDPU_SIZE_INDICATOR) {
+    int i;
+    for(i=len&~TDPU_SIZE_INDICATOR, len=0; i>0; i--) len=(len<<8) + *data++;
+    }
+  return len;
+}
+
+int cScCamSlot::LengthSize(int n)
+{
+  return n<TDPU_SIZE_INDICATOR?1:3;
+}
+
+void cScCamSlot::SetSize(int n, unsigned char * &p)
+{
+  if(n<TDPU_SIZE_INDICATOR) *p++=n;
+  else { *p++=2|TDPU_SIZE_INDICATOR; *p++=n>>8; *p++=n&0xFF; }
+}
+
+void cScCamSlot::CaInfo(int tcid, int cid)
+{
+  int cn=0;
+  for(int i=0; caids[i]; i++) cn+=2;
+  int n=cn+8+LengthSize(cn);
+  unsigned char *p;
+  if(!(p=frame.GetBuff(n+1+LengthSize(n)))) return;
+  *p++=0xa0;
+  SetSize(n,p);
+  *p++=tcid;
+  *p++=0x90;
+  *p++=0x02; *p++=cid>>8; *p++=cid&0xff;
+  *p++=0x9f; *p++=0x80;   *p++=0x31; // AOT_CA_INFO
+  SetSize(cn,p);
+  for(int i=0; caids[i]; i++) { *p++=caids[i]>>8; *p++=caids[i]&0xff; }
+  frame.Put();
+  PRINTF(L_CORE_CI,"%s.%d sending CA info",devId,slot);
+}
+
+void cScCamSlot::Process(const unsigned char *data, int len)
+{
+  const unsigned char *save=data;
+  data+=3;
+  int dlen=GetLength(data);
+  if(dlen>len-(data-save)) {
+    PRINTF(L_CORE_CI,"%s.%d TDPU length exceeds data length",devId,slot);
+    dlen=len-(data-save);
+    }
+  int tcid=data[0];
+
+  if(Check()) CaInfo(tcid,0x01);
+
+  if(dlen<8 || data[1]!=0x90) return;
+  int cid=(data[3]<<8)+data[4];
+  int tag=(data[5]<<16)+(data[6]<<8)+data[7];
+  data+=8;
+  dlen=GetLength(data);
+  if(dlen>len-(data-save)) {
+    PRINTF(L_CORE_CI,"%s.%d tag length exceeds data length",devId,slot);
+    dlen=len-(data-save);
+    }
+  switch(tag) {
+    case 0x9f8030: // AOT_CA_INFO_ENQ
+      CaInfo(tcid,cid);
+      break;
+
+    case 0x9f8032: // AOT_CA_PMT
+      if(dlen>=6) {
+        int ca_lm=data[0];
+        int ci_cmd=-1;
+        cPrg *prg=new cPrg((data[1]<<8)+data[2],ca_lm==5);
+        int ilen=(data[4]<<8)+data[5];
+        LBSTARTF(L_CORE_CI);
+        LBPUT("%s.%d CA_PMT decoding len=%x lm=%x prg=%d len=%x",devId,slot,dlen,ca_lm,(data[1]<<8)+data[2],ilen);
+        data+=6; dlen-=6;
+        LBPUT("/%x",dlen);
+        if(ilen>0 && dlen>=ilen) {
+          ci_cmd=data[0];
+          if(ilen>1)
+            prg->caDescr.Set(&data[1],ilen-1);
+          LBPUT(" ci_cmd(G)=%02x",ci_cmd);
+          }
+        data+=ilen; dlen-=ilen;
+        while(dlen>=5) {
+          cPrgPid *pid=new cPrgPid(data[0],(data[1]<<8)+data[2]);
+          prg->pids.Add(pid);
+          ilen=(data[3]<<8)+data[4];
+          LBPUT(" pid=%d,%x len=%x",data[0],(data[1]<<8)+data[2],ilen);
+          data+=5; dlen-=5;
+          LBPUT("/%x",dlen);
+          if(ilen>0 && dlen>=ilen) {
+            ci_cmd=data[0];
+            if(ilen>1) {
+              pid->caDescr.Set(&data[1],ilen-1);
+              prg->SetPidCaDescr(true);
+              }
+            LBPUT(" ci_cmd(S)=%x",ci_cmd);
+            }
+          data+=ilen; dlen-=ilen;
+          }
+        LBEND();
+        PRINTF(L_CORE_CI,"%s.%d got CA pmt ciCmd=%d caLm=%d",devId,slot,ci_cmd,ca_lm);
+        if(doReply && (ci_cmd==0x03 || (ci_cmd==0x01 && ca_lm==0x03))) {
+          unsigned char *b;
+          if((b=frame.GetBuff(4+11))) {
+            b[0]=0xa0; b[2]=tcid;
+            b[3]=0x90;
+            b[4]=0x02; b[5]=cid<<8; b[6]=cid&0xff;
+            b[7]=0x9f; b[8]=0x80; b[9]=0x33; // AOT_CA_PMT_REPLY
+            b[11]=prg->sid<<8;
+            b[12]=prg->sid&0xff;
+            b[13]=0x00;
+            b[14]=0x81;        // CA_ENABLE
+            b[10]=4; b[1]=4+9;
+            frame.Put();
+            PRINTF(L_CORE_CI,"%s.%d answer to query",devId,slot);
+            }
+          }
+        if(prg->sid!=0) {
+          if(ci_cmd==0x04) {
+            PRINTF(L_CORE_CI,"%s.%d stop decrypt",devId,slot);
+            cam->Stop();
+            }
+          if(ci_cmd==0x01 || (ci_cmd==-1 && (ca_lm==0x04 || ca_lm==0x05))) {
+            PRINTF(L_CORE_CI,"%s.%d set CAM decrypt (prg %d)",devId,slot,prg->sid);
+            cam->AddPrg(prg);
+            }
+          }
+        delete prg;
+        }
+      break;
+    }
+}
+
+#endif //SASC
+
+// -- cCams --------------------------------------------------------------------
+
+class cCams : public cSimpleList<cCam> {
+public:
+  cMutex listMutex;
+  //
+  void Register(cCam *cam);
+  void Unregister(cCam *cam);
+  };
+
+static cCams cams;
+
+void cCams::Register(cCam *cam)
+{
+  cMutexLock lock(&listMutex);
+  Add(cam);
+}
 
-cCam::cCam(cScDevice *dev, int CardNum)
+void cCams::Unregister(cCam *cam)
 {
-  device=dev; cardNum=CardNum;
+  cMutexLock lock(&listMutex);
+  Del(cam,false);
+}
+
+// -- cGlobal ------------------------------------------------------------------
+
+char *cGlobal::CurrKeyStr(int camindex, int num, const char **id)
+{
+  cMutexLock lock(&cams.listMutex);
+  char *str=0;
+  cCam *c;
+  for(c=cams.First(); c && camindex>0; c=cams.Next(c), camindex--);
+  if(c) {
+    str=c->CurrentKeyStr(num,id);
+    if(!str && num==0) str=strdup(tr("(none)"));
+    }
+  return str;
+}
+
+void cGlobal::HouseKeeping(void)
+{
+  cMutexLock lock(&cams.listMutex);
+  for(cCam *c=cams.First(); c; c=cams.Next(c)) c->HouseKeeping();
+}
+
+bool cGlobal::Active(bool log)
+{
+  cMutexLock lock(&cams.listMutex);
+  for(cCam *c=cams.First(); c; c=cams.Next(c)) if(c->Active(log)) return true;
+  return false;
+}
+
+void cGlobal::CaidsChanged(void)
+{
+  cMutexLock lock(&cams.listMutex);
+  PRINTF(L_CORE_CAIDS,"caid list rebuild triggered");
+  for(cCam *c=cams.First(); c; c=cams.Next(c)) c->CaidsChanged();
+}
+
+// -- cCam ---------------------------------------------------------------
+
+struct TPDU {
+  unsigned char slot;
+  unsigned char tcid;
+  unsigned char tag;
+  unsigned char len;
+  unsigned char data[1];
+  };
+
+cCam::cCam(cDevice *Device, int Adapter, int Frontend, const char *DevId, int Cafd, bool SoftCSA, bool FullTS)
+{
+  device=Device; adapter=Adapter; frontend=Frontend; devId=DevId; cafd=Cafd;
+  softcsa=SoftCSA; fullts=FullTS;
+  tcid=0; rebuildcaids=false;
+  memset(version,0,sizeof(version));
+  memset(slots,0,sizeof(slots));
+  SetDescription("SC-CI adapter on device %s",devId);
+  rb=new cRingBufferLinear(KILOBYTE(8),6+LEN_OFF,false,"SC-CI adapter read");
+  if(rb) {
+    rb->SetTimeouts(0,CAM_READ_TIMEOUT);
+    frame.SetRb(rb);
+    BuildCaids(true);
+    slots[0]=new cScCamSlot(this,devId,0);
+    Start();
+    }
+  else PRINTF(L_GEN_ERROR,"failed to create ringbuffer for SC-CI adapter %s.",devId);
+
+  decsa=new cDeCSA(devId);
+
   source=transponder=-1; liveVpid=liveApid=0; logger=0; hookman=0;
   memset(lastCW,0,sizeof(lastCW));
   memset(indexMap,0,sizeof(indexMap));
   memset(splitSid,0,sizeof(splitSid));
+  cams.Register(this);
 }
 
 cCam::~cCam()
 {
+  cams.Unregister(this);
   handlerList.Clear();
   delete hookman;
   delete logger;
+  Cancel(3);
+  ciMutex.Lock();
+  delete rb; rb=0;
+  ciMutex.Unlock();
+  delete decsa; decsa=0;
+}
+
+bool cCam::OwnSlot(const cCamSlot *slot) const
+{
+  if(slots[0]==slot) return true;
+  //for(int i=0; i<MAX_CI_SLOTS; i++) if(slots[i]==slot) return true;
+  return false;
+}
+
+int cCam::GetCaids(int slot, unsigned short *Caids, int max)
+{
+  BuildCaids(false);
+  cMutexLock lock(&ciMutex);
+  if(Caids) {
+    int i;
+    for(i=0; i<MAX_CI_SLOT_CAIDS && i<max && caids[i]; i++) Caids[i]=caids[slot][i];
+    Caids[i]=0;
+    }
+  return version[slot];
+}
+
+void cCam::CaidsChanged(void)
+{
+  rebuildcaids=true;
+}
+
+void cCam::BuildCaids(bool force)
+{
+  if(caidTimer.TimedOut() || force || (rebuildcaids && triggerTimer.TimedOut())) {
+    PRINTF(L_CORE_CAIDS,"%s: building caid lists",devId);
+    cChannelList list(devId);
+    Channels.Lock(false);
+    for(cChannel *channel=Channels.First(); channel; channel=Channels.Next(channel)) {
+      if(!channel->GroupSep() && channel->Ca()>=CA_ENCRYPTED_MIN && device->ProvidesTransponder(channel)) {
+        cChannelCaids *ch=new cChannelCaids(channel);
+        if(ch) list.Add(ch);
+        }
+      }
+    Channels.Unlock();
+    list.Unique(true);
+    list.CheckIgnore();
+    list.Unique(false);
+
+    int n=0, h;
+    caid_t c[MAX_CI_SLOT_CAIDS+1];
+    memset(c,0,sizeof(c));
+    do {
+      if((h=list.Histo())<0) break;
+      c[n++]=h;
+      LBSTART(L_CORE_CAIDS);
+      LBPUT("%s: added %04x caids now",devId,h); for(int i=0; i<n; i++) LBPUT(" %04x",c[i]);
+      LBEND();
+      list.Purge(h,false);
+      } while(n<MAX_CI_SLOT_CAIDS && list.Count()>0);
+    c[n]=0;
+    if(n==0) PRINTF(L_CORE_CI,"%s: no active CAIDs",devId);
+    else if(list.Count()>0) PRINTF(L_GEN_ERROR,"too many CAIDs. You should ignore some CAIDs.");
+
+    ciMutex.Lock();
+    if((version[0]==0 && c[0]!=0) || memcmp(caids[0],c,sizeof(caids[0]))) {
+      memcpy(caids[0],c,sizeof(caids[0]));
+      version[0]++;
+      if(version[0]>0) {
+        LBSTART(L_CORE_CI);
+        LBPUT("card %s, slot %d (v=%2d) caids:",devId,0,version[0]);
+        for(int i=0; caids[0][i]; i++) LBPUT(" %04x",caids[0][i]);
+        LBEND();
+        }
+      }
+    ciMutex.Unlock();
+
+    caidTimer.Set(CAID_TIME);
+    triggerTimer.Set(TRIGGER_TIME);
+    rebuildcaids=false;
+    }
+}
+
+int cCam::Read(unsigned char *Buffer, int MaxLength)
+{
+  cMutexLock lock(&ciMutex);
+  if(rb && Buffer && MaxLength>0) {
+    int s;
+    unsigned char *data=frame.Get(s);
+    if(data) {
+      if(s<=MaxLength) memcpy(Buffer,data,s);
+      else PRINTF(L_GEN_DEBUG,"internal: sc-ci %s rb frame size exceeded %d",devId,s);
+      frame.Del();
+      if(Buffer[2]!=0x80 || LOG(L_CORE_CIFULL)) {
+        LDUMP(L_CORE_CI,Buffer,s,"%s.%d <-",devId,Buffer[0]);
+        readTimer.Set();
+        }
+      return s;
+      }
+    }
+  else cCondWait::SleepMs(CAM_READ_TIMEOUT);
+  if(LOG(L_CORE_CIFULL) && readTimer.Elapsed()>2000) {
+    PRINTF(L_CORE_CIFULL,"%s: read heartbeat",devId);
+    readTimer.Set();
+    }
+  return 0;
+}
+
+#define TPDU(data,slot)   do { unsigned char *_d=(data); _d[0]=(slot); _d[1]=tcid; } while(0)
+#define TAG(data,tag,len) do { unsigned char *_d=(data); _d[0]=(tag); _d[1]=(len); } while(0)
+#define SB_TAG(data,sb)   do { unsigned char *_d=(data); _d[0]=0x80; _d[1]=0x02; _d[2]=tcid; _d[3]=(sb); } while(0)
+
+void cCam::Write(const unsigned char *buff, int len)
+{
+  cMutexLock lock(&ciMutex);
+  if(buff && len>=5) {
+    struct TPDU *tpdu=(struct TPDU *)buff;
+    int slot=tpdu->slot;
+    cCiFrame *slotframe=slots[slot]->Frame();
+    if(buff[2]!=0xA0 || buff[3]>0x01 || LOG(L_CORE_CIFULL))
+      LDUMP(L_CORE_CI,buff,len,"%s.%d ->",devId,slot);
+    if(slots[slot]) {
+      switch(tpdu->tag) {
+        case 0x81: // T_RCV
+          {
+          int s;
+          unsigned char *d=slotframe->Get(s);
+          if(d) {
+            unsigned char *b;
+            if((b=frame.GetBuff(s+6))) {
+              TPDU(b,slot);
+              memcpy(b+2,d,s);
+              slotframe->Del(); // delete from rb before Avail()
+              SB_TAG(b+2+s,slotframe->Avail()>0 ? 0x80:0x00);
+              frame.Put();
+              }
+            else slotframe->Del();
+            }
+          break;
+          }
+        case 0x82: // T_CREATE_TC
+          {
+          tcid=tpdu->data[0];
+          unsigned char *b;
+          static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 };
+          if((b=slotframe->GetBuff(sizeof(reqCAS)))) {
+            memcpy(b,reqCAS,sizeof(reqCAS));
+            b[2]=tcid;
+            slotframe->Put();
+            }
+          if((b=frame.GetBuff(9))) {
+            TPDU(b,slot);
+            TAG(&b[2],0x83,0x01); b[4]=tcid;
+            SB_TAG(&b[5],slotframe->Avail()>0 ? 0x80:0x00);
+            frame.Put();
+            }
+          break;
+          }
+        case 0xA0: // T_DATA_LAST
+          {
+          slots[slot]->Process(buff,len);
+          unsigned char *b;
+          if((b=frame.GetBuff(6))) {
+            TPDU(b,slot);
+            SB_TAG(&b[2],slotframe->Avail()>0 ? 0x80:0x00);
+            frame.Put();
+            }
+          break;
+          }
+        }
+      }
+    }
+  else PRINTF(L_CORE_CIFULL,"%s: short write (buff=%d len=%d)",devId,buff!=0,len);
+}
+
+bool cCam::Reset(int Slot)
+{
+  cMutexLock lock(&ciMutex);
+  PRINTF(L_CORE_CI,"%s: reset of slot %d requested",devId,Slot);
+  return slots[Slot] ? slots[Slot]->Reset():false;
+}
+
+eModuleStatus cCam::ModuleStatus(int Slot)
+{
+  cMutexLock lock(&ciMutex);
+  bool enable=ScSetup.CapCheck(device->CardIndex());
+  if(!enable) Stop();
+  return (enable && slots[Slot]) ? slots[Slot]->Status():msNone;
+}
+
+bool cCam::Assign(cDevice *Device, bool Query)
+{
+  return Device ? (Device==device) : true;
 }
 
 bool cCam::IsSoftCSA(bool live)
 {
-  return device->SoftCSA(live);
+  return softcsa && (!fullts || !live);
 }
 
 void cCam::Tune(const cChannel *channel)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   if(source!=channel->Source() || transponder!=channel->Transponder()) {
     source=channel->Source(); transponder=channel->Transponder();
-    PRINTF(L_CORE_PIDS,"%d: now tuned to source %x(%s) transponder %x",cardNum,source,*cSource::ToString(source),transponder);
+    PRINTF(L_CORE_PIDS,"%s: now tuned to source %x(%s) transponder %x",devId,source,*cSource::ToString(source),transponder);
     Stop();
     }
-  else PRINTF(L_CORE_PIDS,"%d: tune to same source/transponder",cardNum);
+  else PRINTF(L_CORE_PIDS,"%s: tune to same source/transponder",devId);
 }
 
 void cCam::PostTune(void)
@@ -1374,19 +2340,19 @@ void cCam::PostTune(void)
 
 void cCam::SetPid(int type, int pid, bool on)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   int oldA=liveApid, oldV=liveVpid;
   if(type==1) liveVpid=on ? pid:0;
   else if(type==0) liveApid=on ? pid:0;
   else if(liveVpid==pid && on) liveVpid=0;
   else if(liveApid==pid && on) liveApid=0;
   if(oldA!=liveApid || oldV!=liveVpid)
-    PRINTF(L_CORE_PIDS,"%d: livepids video=%04x audio=%04x",cardNum,liveVpid,liveApid);
+    PRINTF(L_CORE_PIDS,"%s: livepids video=%04x audio=%04x",devId,liveVpid,liveApid);
 }
 
 void cCam::Stop(void)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler))
     handler->Stop();
   if(logger) logger->Down();
@@ -1396,7 +2362,7 @@ void cCam::Stop(void)
 
 void cCam::AddPrg(cPrg *prg)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   bool islive=false;
   for(cPrgPid *pid=prg->pids.First(); pid; pid=prg->pids.Next(pid))
     if(pid->pid==liveVpid || pid->pid==liveApid) {
@@ -1405,10 +2371,10 @@ void cCam::AddPrg(cPrg *prg)
       }
   bool needZero=!IsSoftCSA(islive) && (islive || !ScSetup.ConcurrentFF);
   bool noshift=IsSoftCSA(true) || (prg->IsUpdate() && prg->pids.Count()==0);
-  PRINTF(L_CORE_PIDS,"%d: %s SID %d (zero=%d noshift=%d)",cardNum,prg->IsUpdate()?"update":"add",prg->sid,needZero,noshift);
+  PRINTF(L_CORE_PIDS,"%s: %s SID %d (zero=%d noshift=%d)",devId,prg->IsUpdate()?"update":"add",prg->sid,needZero,noshift);
   if(prg->pids.Count()>0) {
     LBSTART(L_CORE_PIDS);
-    LBPUT("%d: pids",cardNum);
+    LBPUT("%s: pids",devId);
     for(cPrgPid *pid=prg->pids.First(); pid; pid=prg->pids.Next(pid))
       LBPUT(" %s=%04x",TYPENAME(pid->type),pid->pid);
     LBEND();
@@ -1422,14 +2388,14 @@ void cCam::AddPrg(cPrg *prg)
   if(!isSplit) {
     cEcmHandler *handler=GetHandler(prg->sid,needZero,noshift);
     if(handler) {
-      PRINTF(L_CORE_PIDS,"%d: found handler for SID %d (%s idle=%d idx=%d)",cardNum,prg->sid,handler->Id(),handler->IsIdle(),handler->CwIndex());
+      PRINTF(L_CORE_PIDS,"%s: found handler for SID %d (%s idle=%d idx=%d)",devId,prg->sid,handler->Id(),handler->IsIdle(),handler->CwIndex());
       prg->source=source;
       prg->transponder=transponder;
       handler->SetPrg(prg);
       }
     }
   else {
-    PRINTF(L_CORE_PIDS,"%d: SID %d is handled as splitted",cardNum,prg->sid);
+    PRINTF(L_CORE_PIDS,"%s: SID %d is handled as splitted",devId,prg->sid);
     // first update the splitSid list
     if(prg->pids.Count()==0) { // delete
       for(int i=0; splitSid[i]; i++)
@@ -1437,7 +2403,7 @@ void cCam::AddPrg(cPrg *prg)
           memmove(&splitSid[i],&splitSid[i+1],sizeof(splitSid[0])*(MAX_SPLIT_SID-i));
           break;
           }
-      PRINTF(L_CORE_PIDS,"%d: deleted from list",cardNum);
+      PRINTF(L_CORE_PIDS,"%s: deleted from list",devId);
       }
     else { // add
       bool has=false;
@@ -1447,13 +2413,13 @@ void cCam::AddPrg(cPrg *prg)
         if(i<MAX_SPLIT_SID) {
           splitSid[i]=prg->sid;
           splitSid[i+1]=0;
-          PRINTF(L_CORE_PIDS,"%d: added to list",cardNum);
+          PRINTF(L_CORE_PIDS,"%s: added to list",devId);
           }
-        else PRINTF(L_CORE_PIDS,"%d: split SID list overflow",cardNum);
+        else PRINTF(L_CORE_PIDS,"%s: split SID list overflow",devId);
         }
       }
     LBSTART(L_CORE_PIDS);
-    LBPUT("%d: split SID list now:",cardNum);
+    LBPUT("%s: split SID list now:",devId);
     for(int i=0; i<=MAX_SPLIT_SID; i++) LBPUT(" %d",splitSid[i]);
     LBEND();
     // prepare an empty prg head
@@ -1465,7 +2431,7 @@ void cCam::AddPrg(cPrg *prg)
     cPrgPid *first;
     while((first=prg->pids.First())) {
       LBSTARTF(L_CORE_PIDS);
-      LBPUT("%d: group %d pids",cardNum,group);
+      LBPUT("%s: group %d pids",devId,group);
       prg->pids.Del(first,false);
       work.caDescr.Set(&first->caDescr);
       first->caDescr.Clear();
@@ -1498,7 +2464,7 @@ void cCam::AddPrg(cPrg *prg)
       // otherwise get the group-sid handler
       if(!handler) handler=GetHandler(grsid,needZero,noshift);
       if(handler) {
-        PRINTF(L_CORE_PIDS,"%d: found handler for group-SID %d (%s idle=%d idx=%d)",cardNum,grsid,handler->Id(),handler->IsIdle(),handler->CwIndex());
+        PRINTF(L_CORE_PIDS,"%s: found handler for group-SID %d (%s idle=%d idx=%d)",devId,grsid,handler->Id(),handler->IsIdle(),handler->CwIndex());
         work.sid=grsid;
         handler->SetPrg(&work);
         }
@@ -1514,7 +2480,7 @@ void cCam::AddPrg(cPrg *prg)
         int gr=sid/SIDGRP_SHIFT;
         sid%=SIDGRP_SHIFT;
         if(sid==prg->sid && gr>=group) {
-          PRINTF(L_CORE_PIDS,"%d: idle group handler %s idx=%d",cardNum,handler->Id(),handler->CwIndex());
+          PRINTF(L_CORE_PIDS,"%s: idle group handler %s idx=%d",devId,handler->Id(),handler->CwIndex());
           work.sid=handler->Sid();
           handler->SetPrg(&work);
           }
@@ -1525,16 +2491,17 @@ void cCam::AddPrg(cPrg *prg)
 
 bool cCam::HasPrg(int prg)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler))
     if(!handler->IsIdle() && handler->Sid()==prg)
       return true;
   return false;
 }
 
-char *cCam::CurrentKeyStr(int num)
+char *cCam::CurrentKeyStr(int num, const char **id)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
+  if(id) *id=devId;
   cEcmHandler *handler;
   for(handler=handlerList.First(); handler; handler=handlerList.Next(handler))
     if(--num<0) return handler->CurrentKeyStr();
@@ -1543,10 +2510,10 @@ char *cCam::CurrentKeyStr(int num)
 
 bool cCam::Active(bool log)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   for(cEcmHandler *handler=handlerList.First(); handler; handler=handlerList.Next(handler))
     if(!handler->IsIdle()) {
-      if(log) PRINTF(L_GEN_INFO,"handler %s on card %d is not idle",handler->Id(),cardNum);
+      if(log) PRINTF(L_GEN_INFO,"handler %s on card %s is not idle",handler->Id(),devId);
       return true;
       }
   return false;
@@ -1554,7 +2521,7 @@ bool cCam::Active(bool log)
 
 void cCam::HouseKeeping(void)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   for(cEcmHandler *handler=handlerList.First(); handler;) {
     cEcmHandler *next=handlerList.Next(handler);
     if(handler->IsRemoveable()) RemHandler(handler);
@@ -1568,24 +2535,24 @@ void cCam::HouseKeeping(void)
 
 void cCam::LogStartup(void)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   if(!logger && ScSetup.AutoUpdate) {
-    logger=new cLogger(cardNum,IsSoftCSA(false));
+    logger=new cLogger(this,device,devId,IsSoftCSA(false));
     LogStatsUp();
     }
 }
 
 void cCam::LogEcmStatus(const cEcmInfo *ecm, bool on)
 {
-  cMutexLock lock(this);
+  cMutexLock lock(&camMutex);
   if(on) LogStartup();
   if(logger) logger->EcmStatus(ecm,on);
 }
 
 void cCam::AddHook(cLogHook *hook)
 {
-  cMutexLock lock(this);
-  if(!hookman) hookman=new cHookManager(cardNum);
+  cMutexLock lock(&camMutex);
+  if(!hookman) hookman=new cHookManager(device,devId);
   if(hookman) hookman->AddHook(hook);
 }
 
@@ -1600,8 +2567,8 @@ void cCam::SetCWIndex(int pid, int index)
     ca_pid_t ca_pid;
     ca_pid.pid=pid;
     ca_pid.index=index;
-    PRINTF(L_CORE_PIDS,"%d: descrambling pid %04x on index %x",cardNum,pid,index);
-    if(!device->SetCaPid(&ca_pid))
+    PRINTF(L_CORE_PIDS,"%s: descrambling pid %04x on index %x",devId,pid,index);
+    if(!SetCaPid(&ca_pid))
       if(index>0) {
         PRINTF(L_GEN_ERROR,"CA_SET_PID failed (%s). Expect a black screen/bad recording. Do you use the patched DVB driver?",strerror(errno));
         PRINTF(L_GEN_WARN,"Adjusting 'Concurrent FF streams' to NO");
@@ -1622,7 +2589,7 @@ void cCam::WriteCW(int index, unsigned char *cw, bool force)
       memcpy(&last[0],&cw[0],8);
       ca_descr.parity=0;
       memcpy(ca_descr.cw,&cw[0],8);
-      if(!device->SetCaDescr(&ca_descr,force))
+      if(!SetCaDescr(&ca_descr,force))
         PRINTF(L_GEN_ERROR,"CA_SET_DESCR failed (%s). Expect a black screen.",strerror(errno));
       }
 
@@ -1630,15 +2597,115 @@ void cCam::WriteCW(int index, unsigned char *cw, bool force)
       memcpy(&last[8],&cw[8],8);
       ca_descr.parity=1;
       memcpy(ca_descr.cw,&cw[8],8);
-      if(!device->SetCaDescr(&ca_descr,force))
+      if(!SetCaDescr(&ca_descr,force))
         PRINTF(L_GEN_ERROR,"CA_SET_DESCR failed (%s). Expect a black screen.",strerror(errno));
       }
     }
 }
 
+bool cCam::SetCaDescr(ca_descr_t *ca_descr, bool initial)
+{
+#ifndef SASC
+  if(!softcsa || (fullts && ca_descr->index==0)) {
+    cMutexLock lock(&cafdMutex);
+    return ioctl(cafd,CA_SET_DESCR,ca_descr)>=0;
+    }
+  else if(decsa) return decsa->SetDescr(ca_descr,initial);
+#endif // !SASC
+  return false;
+}
+
+bool cCam::SetCaPid(ca_pid_t *ca_pid)
+{
+#ifndef SASC
+  if(!softcsa || (fullts && ca_pid->index==0)) {
+    cMutexLock lock(&cafdMutex);
+    return ioctl(cafd,CA_SET_PID,ca_pid)>=0;
+    }
+  else if(decsa) return decsa->SetCaPid(ca_pid);
+#endif // !SASC
+  return false;
+}
+
+#ifndef SASC
+static unsigned int av7110_read(int fd, unsigned int addr)
+{
+  ca_pid_t arg;
+  arg.pid=addr;
+  ioctl(fd,CA_GET_MSG,&arg);
+  return arg.index;
+}
+#endif // !SASC
+
+#if 0
+static void av7110_write(int fd, unsigned int addr, unsigned int val)
+{
+  ca_pid_t arg;
+  arg.pid=addr;
+  arg.index=val;
+  ioctl(fd,CA_SEND_MSG,&arg);
+}
+#endif
+
 void cCam::DumpAV7110(void)
 {
-  device->DumpAV7110();
+#ifndef SASC
+  if(LOG(L_CORE_AV7110)) {
+#define CODEBASE (0x2e000404+0x1ce00)
+    cMutexLock lock(&cafdMutex);
+    if(device->HasDecoder() && lastDump.Elapsed()>20000) {
+      lastDump.Set();
+      static unsigned int handles=0, hw_handles=0;
+      static const unsigned int code[] = {
+        0xb5100040,0x4a095a12,0x48094282,0xd00b4b09,0x20000044,
+        0x5b1c4294,0xd0033001,0x281cdbf8,0xe001f7fe,0xfd14bc10
+        };
+      static const unsigned int mask[] = {
+        0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+        0xffffffff,0xffffffff,0xffffffff,0xfffff800,0xf800ffff
+        };
+      if(!handles) {
+        handles=1;
+        PRINTF(L_CORE_AV7110,"searching handle tables");
+        for(int i=0; i<0x2000; i+=4) {
+          int j;
+          for(j=0; j<20; j+=4) {
+            int r=av7110_read(cafd,CODEBASE+i+j);
+            if((r&mask[j/4])!=(code[j/4]&mask[j/4])) break;
+            }
+          if(j==20) {
+            handles=av7110_read(cafd,CODEBASE+i+44);
+            hw_handles=av7110_read(cafd,CODEBASE+i+52);
+            PRINTF(L_CORE_AV7110,"found handles=%08x hw_handles=%08x at 0x%08x",handles,hw_handles,CODEBASE+i);
+            if((handles>>16)!=0x2e08 || (hw_handles>>16)!=0x2e08) {
+              PRINTF(L_CORE_AV7110,"seems to be invalid");
+              }
+            break;
+            }
+          }
+        }
+
+      unsigned int hdl=0, hwhdl=0;
+      PRINTF(L_CORE_AV7110,"         : 64000080 64000400");
+      for(int i=0; i<=31; i++) {
+        unsigned int off80 =av7110_read(cafd,0x64000080+i*4);
+        unsigned int off400=av7110_read(cafd,0x64000400+i*8);
+        LBSTART(L_CORE_AV7110);
+        LBPUT("handle %2d: %08x %08x %s pid=%04x idx=%d",
+          i,off80,off400,off80&0x2000?"ACT":"---",off80&0x1fff,(off400&0x1e)>>1);
+        if(handles>1 && i<=27) {
+          if((i&1)==0) {
+            hdl=av7110_read(cafd,handles+i*2);
+            hwhdl=av7110_read(cafd,hw_handles+i*2);
+            }
+          unsigned int s=((~i)&1)<<4;
+          LBPUT(" | %02d hdl=%04x hwfilt=%04x",i,(hdl>>s)&0xffff,(hwhdl>>s)&0xffff);
+          }
+        LBEND();
+        }
+      }
+    }
+#endif // !SASC
 }
 
 int cCam::GetFreeIndex(void)
@@ -1660,7 +2727,7 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
       idlehandler=handler;
     }
   LBSTART(L_CORE_PIDS);
-  LBPUT("%d: SID=%d zero=%d |",cardNum,sid,needZero);
+  LBPUT("%s: SID=%d zero=%d |",devId,sid,needZero);
   if(sidhandler) LBPUT(" sid=%d/%d/%d",sidhandler->CwIndex(),sidhandler->Sid(),sidhandler->IsIdle());
   else LBPUT(" sid=-/-/-");
   if(zerohandler) LBPUT(" zero=%d/%d/%d",zerohandler->CwIndex(),zerohandler->Sid(),zerohandler->IsIdle());
@@ -1672,10 +2739,10 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
   if(sidhandler) {
     if(needZero && sidhandler->CwIndex()!=0 && !noshift) {
       if(!sidhandler->IsIdle())
-        PRINTF(L_CORE_ECM,"%d: shifting cwindex on non-idle handler.",cardNum);
+        PRINTF(L_CORE_ECM,"%s: shifting cwindex on non-idle handler.",devId);
       if(zerohandler) {
         if(!zerohandler->IsIdle())
-          PRINTF(L_CORE_ECM,"%d: shifting non-idle zero handler. This shouldn't happen!",cardNum);
+          PRINTF(L_CORE_ECM,"%s: shifting non-idle zero handler. This shouldn't happen!",devId);
         zerohandler->ShiftCwIndex(sidhandler->CwIndex());
         sidhandler->ShiftCwIndex(0);
         }
@@ -1684,19 +2751,19 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
         indexMap[sidhandler->CwIndex()]=0;
         sidhandler->ShiftCwIndex(0);
         }
-      else PRINTF(L_CORE_ECM,"%d: zero index not free.",cardNum);
+      else PRINTF(L_CORE_ECM,"%s: zero index not free.",devId);
       }
 
     if(!needZero && sidhandler->CwIndex()==0 && !noshift) {
       if(!sidhandler->IsIdle())
-        PRINTF(L_CORE_ECM,"%d: shifting cwindex on non-idle handler.",cardNum);
+        PRINTF(L_CORE_ECM,"%s: shifting cwindex on non-idle handler.",devId);
       int idx=GetFreeIndex();
       if(idx>=0) {
         indexMap[idx]=1;
         sidhandler->ShiftCwIndex(idx);
         indexMap[0]=0;
         }
-      else PRINTF(L_CORE_ECM,"%d: no free cwindex. Can't free zero index.",cardNum);
+      else PRINTF(L_CORE_ECM,"%s: no free cwindex. Can't free zero index.",devId);
       }
 
     return sidhandler;
@@ -1704,7 +2771,7 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
 
   if(needZero && zerohandler) {
     if(!zerohandler->IsIdle())
-      PRINTF(L_CORE_ECM,"%d: changing SID on non-idle zero handler. This shouldn't happen!",cardNum);
+      PRINTF(L_CORE_ECM,"%s: changing SID on non-idle zero handler. This shouldn't happen!",devId);
     return zerohandler;
     }
   
@@ -1715,7 +2782,7 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
         indexMap[idlehandler->CwIndex()]=0;
         idlehandler->ShiftCwIndex(0);
         }
-      else PRINTF(L_CORE_ECM,"%d: zero index not free. (2)",cardNum);
+      else PRINTF(L_CORE_ECM,"%s: zero index not free. (2)",devId);
       }
     if(!needZero && idlehandler->CwIndex()==0 && !noshift) {
       int idx=GetFreeIndex();
@@ -1724,10 +2791,10 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
         idlehandler->ShiftCwIndex(idx);
         indexMap[0]=0;
         }
-      else PRINTF(L_CORE_ECM,"%d: no free cwindex. Can't free zero index. (2)",cardNum);
+      else PRINTF(L_CORE_ECM,"%s: no free cwindex. Can't free zero index. (2)",devId);
       }
     if((needZero ^ (idlehandler->CwIndex()==0)))
-      PRINTF(L_CORE_ECM,"%d: idlehandler index doesn't match needZero",cardNum);
+      PRINTF(L_CORE_ECM,"%s: idlehandler index doesn't match needZero",devId);
     return idlehandler;
     }
 
@@ -1738,15 +2805,15 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
     indexMap[0]=0;
     if(idx<0) {
       idx=0;
-      PRINTF(L_CORE_ECM,"%d: can't respect !needZero for new handler",cardNum);
+      PRINTF(L_CORE_ECM,"%s: can't respect !needZero for new handler",devId);
       }
     }
   if(idx<0) {
-    PRINTF(L_CORE_ECM,"%d: no free cwindex",cardNum);
+    PRINTF(L_CORE_ECM,"%s: no free cwindex",devId);
     return 0;
     }
   indexMap[idx]=1;
-  idlehandler=new cEcmHandler(this,cardNum,idx);
+  idlehandler=new cEcmHandler(this,device,devId,idx);
   handlerList.Add(idlehandler);
   return idlehandler;
 }
@@ -1754,7 +2821,204 @@ cEcmHandler *cCam::GetHandler(int sid, bool needZero, bool noshift)
 void cCam::RemHandler(cEcmHandler *handler)
 {
   int idx=handler->CwIndex();
-  PRINTF(L_CORE_PIDS,"%d: removing %s on cw index %d",cardNum,handler->Id(),idx);
+  PRINTF(L_CORE_PIDS,"%s: removing %s on cw index %d",devId,handler->Id(),idx);
   handlerList.Del(handler);
   indexMap[idx]=0;
 }
+
+// -- cDeCSA -------------------------------------------------------------------
+
+#define MAX_STALL_MS 70
+
+#define MAX_REL_WAIT 100 // time to wait if key in used on set
+#define MAX_KEY_WAIT 500 // time to wait if key not ready on change
+
+#define FL_EVEN_GOOD 1
+#define FL_ODD_GOOD  2
+#define FL_ACTIVITY  4
+
+
+cDeCSA::cDeCSA(const char *DevId)
+:stall(MAX_STALL_MS)
+{
+  devId=DevId;
+  cs=get_suggested_cluster_size();
+  PRINTF(L_CORE_CSA,"%s: clustersize=%d rangesize=%d",devId,cs,cs*2+5);
+  range=MALLOC(unsigned char *,(cs*2+5));
+  memset(keys,0,sizeof(keys));
+  memset(pidmap,0,sizeof(pidmap));
+  ResetState();
+}
+
+cDeCSA::~cDeCSA()
+{
+  for(int i=0; i<MAX_CSA_IDX; i++)
+    if(keys[i]) free_key_struct(keys[i]);
+  free(range);
+}
+
+void cDeCSA::ResetState(void)
+{
+  PRINTF(L_CORE_CSA,"%s: reset state",devId);
+  memset(even_odd,0,sizeof(even_odd));
+  memset(flags,0,sizeof(flags));
+  lastData=0;
+}
+
+void cDeCSA::SetActive(bool on)
+{
+  if(!on && active) ResetState();
+  active=on;
+  PRINTF(L_CORE_CSA,"%s: set active %s",devId,active?"on":"off");
+}
+
+bool cDeCSA::GetKeyStruct(int idx)
+{
+  if(!keys[idx]) keys[idx]=get_key_struct();
+  return keys[idx]!=0;
+}
+
+bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
+{
+  cMutexLock lock(&mutex);
+  int idx=ca_descr->index;
+  if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) {
+    if(!initial && active && ca_descr->parity==(even_odd[idx]&0x40)>>6) {
+      if(flags[idx] & (ca_descr->parity?FL_ODD_GOOD:FL_EVEN_GOOD)) {
+        PRINTF(L_CORE_CSA,"%s.%d: %s key in use (%d ms)",devId,idx,ca_descr->parity?"odd":"even",MAX_REL_WAIT);
+        if(wait.TimedWait(mutex,MAX_REL_WAIT)) PRINTF(L_CORE_CSA,"%s.%d: successfully waited for release",devId,idx);
+        else PRINTF(L_CORE_CSA,"%s.%d: timed out. setting anyways",devId,idx);
+        }
+      else PRINTF(L_CORE_CSA,"%s.%d: late key set...",devId,idx);
+      }
+    LDUMP(L_CORE_CSA,ca_descr->cw,8,"%s.%d: %4s key set",devId,idx,ca_descr->parity?"odd":"even");
+    if(ca_descr->parity==0) {
+      set_even_control_word(keys[idx],ca_descr->cw);
+      if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_EVEN_GOOD|FL_ACTIVITY;
+      else PRINTF(L_CORE_CSA,"%s.%d: zero even CW",devId,idx);
+      wait.Broadcast();
+      }
+    else {
+      set_odd_control_word(keys[idx],ca_descr->cw);
+      if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_ODD_GOOD|FL_ACTIVITY;
+      else PRINTF(L_CORE_CSA,"%s.%d: zero odd CW",devId,idx);
+      wait.Broadcast();
+      }
+    }
+  return true;
+}
+
+bool cDeCSA::SetCaPid(ca_pid_t *ca_pid)
+{
+  cMutexLock lock(&mutex);
+  if(ca_pid->index<MAX_CSA_IDX && ca_pid->pid<MAX_CSA_PIDS) {
+    pidmap[ca_pid->pid]=ca_pid->index;
+    PRINTF(L_CORE_CSA,"%s.%d: set pid %04x",devId,ca_pid->index,ca_pid->pid);
+    }
+  return true;
+}
+
+bool cDeCSA::Decrypt(unsigned char *data, int len, bool force)
+{
+  cMutexLock lock(&mutex);
+  int r=-2, ccs=0, currIdx=-1;
+  bool newRange=true;
+  range[0]=0;
+  len-=(TS_SIZE-1);
+  int l;
+  for(l=0; l<len; l+=TS_SIZE) {
+    if(data[l]!=TS_SYNC_BYTE) {       // let higher level cope with that
+      PRINTF(L_CORE_CSA,"%s: garbage in TS buffer",devId);
+      if(ccs) force=true;             // prevent buffer stall
+      break;
+      }
+    unsigned int ev_od=data[l+3]&0xC0;
+    if(ev_od==0x80 || ev_od==0xC0) { // encrypted
+      int idx=pidmap[((data[l+1]<<8)+data[l+2])&(MAX_CSA_PIDS-1)];
+      if(currIdx<0 || idx==currIdx) { // same or no index
+        currIdx=idx;
+        if(ccs==0 && ev_od!=even_odd[idx]) {
+          even_odd[idx]=ev_od;
+          wait.Broadcast();
+          PRINTF(L_CORE_CSA,"%s.%d: change to %s key",devId,idx,(ev_od&0x40)?"odd":"even");
+          bool doWait=false;
+          if(ev_od&0x40) {
+            flags[idx]&=~FL_EVEN_GOOD;
+            if(!(flags[idx]&FL_ODD_GOOD)) doWait=true;
+            }
+          else {
+            flags[idx]&=~FL_ODD_GOOD;
+            if(!(flags[idx]&FL_EVEN_GOOD)) doWait=true;
+            }
+          if(doWait) {
+            PRINTF(L_CORE_CSA,"%s.%d: %s key not ready (%d ms)",devId,idx,(ev_od&0x40)?"odd":"even",MAX_KEY_WAIT);
+            if(flags[idx]&FL_ACTIVITY) {
+              flags[idx]&=~FL_ACTIVITY;
+              if(wait.TimedWait(mutex,MAX_KEY_WAIT)) PRINTF(L_CORE_CSA,"%s.%d: successfully waited for key",devId,idx);
+              else PRINTF(L_CORE_CSA,"%s.%d: timed out. proceeding anyways",devId,idx);
+              }
+            else PRINTF(L_CORE_CSA,"%s.%d: not active. wait skipped",devId,idx);
+            }
+          }
+        if(newRange) {
+          r+=2; newRange=false;
+          range[r]=&data[l];
+          range[r+2]=0;
+          }
+        range[r+1]=&data[l+TS_SIZE];
+        if(++ccs>=cs) break;
+        }
+      else newRange=true;             // other index, create hole
+      }
+    else {                            // unencrypted
+      // nothing, we don't create holes for unencrypted packets
+      }
+    }
+  int scanTS=l/TS_SIZE;
+  int stallP=ccs*100/scanTS;
+
+  LBSTART(L_CORE_CSAVERB);
+  LBPUT("%s: %s-%d-%d : %d-%d-%d stall=%d :: ",
+        devId,data==lastData?"SAME":"MOVE",(len+(TS_SIZE-1))/TS_SIZE,force,
+        currIdx,ccs,scanTS,stallP);
+  for(int l=0; l<len; l+=TS_SIZE) {
+    if(data[l]!=TS_SYNC_BYTE) break;
+    unsigned int ev_od=data[l+3]&0xC0;
+    if(ev_od&0x80) {
+      int pid=(data[l+1]<<8)+data[l+2];
+      int idx=pidmap[pid&(MAX_CSA_PIDS-1)];
+      LBPUT("%s/%x/%d ",(ev_od&0x40)?"o":"e",pid,idx);
+      }
+    else {
+      LBPUT("*/%x ",(data[l+1]<<8)+data[l+2]);
+      }
+    }
+  LBEND();
+
+  if(r>=0 && ccs<cs && !force) {
+    if(lastData==data && stall.TimedOut()) {
+      PRINTF(L_CORE_CSAVERB,"%s: stall timeout -> forced",devId);
+      force=true;
+      }
+    else if(stallP<=10 && scanTS>=cs) {
+      PRINTF(L_CORE_CSAVERB,"%s: flow factor stall -> forced",devId);
+      force=true;
+      }
+    }
+  lastData=data;
+
+  if(r>=0) {                          // we have some range
+    if(ccs>=cs || force) {
+      if(GetKeyStruct(currIdx)) {
+        int n=decrypt_packets(keys[currIdx],range);
+        PRINTF(L_CORE_CSAVERB,"%s.%d: decrypting ccs=%3d cs=%3d %s -> %3d decrypted",devId,currIdx,ccs,cs,ccs>=cs?"OK ":"INC",n);
+        if(n>0) {
+          stall.Set(MAX_STALL_MS);
+          return true;
+          }
+        }
+      }
+    else PRINTF(L_CORE_CSAVERB,"%s.%d: incomplete ccs=%3d cs=%3d",devId,currIdx,ccs,cs);
+    }
+  return false;
+}
diff --git a/cam.h b/cam.h
index 41ed871500633654598aef26ce1d06771e49dde3..de6b1e413fa80c0d92013611a6f4731497dc5bdb 100644 (file)
--- a/cam.h
+++ b/cam.h
 #ifndef ___CAM_H
 #define ___CAM_H
 
+#include <linux/dvb/ca.h>
+#include <vdr/ci.h>
 #include <vdr/thread.h>
 #include "data.h"
 #include "misc.h"
 
 class cChannel;
+class cRingBufferLinear;
+class cDevice;
 
 class cEcmHandler;
 class cEcmData;
 class cLogger;
 class cHookManager;
 class cLogHook;
-class cScDevice;
+class cScCamSlot;
+class cCiFrame;
+class cDeCSA;
 class cPrg;
 
 // ----------------------------------------------------------------
@@ -53,13 +59,61 @@ extern cEcmCache ecmcache;
 
 // ----------------------------------------------------------------
 
+class cCiFrame {
+private:
+  cRingBufferLinear *rb;
+  unsigned char *mem;
+  int len, alen, glen;
+public:
+  cCiFrame(void);
+  ~cCiFrame();
+  void SetRb(cRingBufferLinear *Rb) { rb=Rb; }
+  unsigned char *GetBuff(int l);
+  void Put(void);
+  unsigned char *Get(int &l);
+  void Del(void);
+  int Avail(void);
+  };
+
+// ----------------------------------------------------------------
+
+typedef int caid_t;
+
+#define MAX_CI_SLOTS      8
+#ifdef VDR_MAXCAID
+#define MAX_CI_SLOT_CAIDS VDR_MAXCAID
+#else
+#define MAX_CI_SLOT_CAIDS 16
+#endif
+
 #define MAX_CW_IDX        16
 #define MAX_SPLIT_SID     16
 
-class cCam : private cMutex {
+class cCam : public cCiAdapter, public cSimpleItem {
 private:
-  int cardNum;
-  cScDevice *device;
+  cDevice *device;
+  cMutex ciMutex;
+  const char *devId;
+  int adapter, frontend;
+  cRingBufferLinear *rb;
+  cScCamSlot *slots[MAX_CI_SLOTS];
+  cCiFrame frame;
+  //
+  cDeCSA *decsa;
+  int cafd;
+  cMutex cafdMutex;
+  bool softcsa, fullts;
+  //
+  cTimeMs caidTimer, triggerTimer;
+  int version[MAX_CI_SLOTS];
+  caid_t caids[MAX_CI_SLOTS][MAX_CI_SLOT_CAIDS+1];
+  int tcid;
+  bool rebuildcaids;
+  //
+  cTimeMs readTimer, writeTimer;
+  cTimeMs lastDump;
+  //
+  cMutex camMutex;
   cSimpleList<cEcmHandler> handlerList;
   cLogger *logger;
   cHookManager *hookman;
@@ -67,17 +121,36 @@ private:
   int splitSid[MAX_SPLIT_SID+1];
   unsigned char indexMap[MAX_CW_IDX], lastCW[MAX_CW_IDX][2*8];
   //
+  void BuildCaids(bool force);
   cEcmHandler *GetHandler(int sid, bool needZero, bool noshift);
   void RemHandler(cEcmHandler *handler);
   int GetFreeIndex(void);
   void LogStartup(void);
+protected:
+  virtual int Read(unsigned char *Buffer, int MaxLength);
+  virtual void Write(const unsigned char *Buffer, int Length);
+  virtual bool Reset(int Slot);
+  virtual eModuleStatus ModuleStatus(int Slot);
+  virtual bool Assign(cDevice *Device, bool Query=false);
 public:
-  cCam(cScDevice *dev, int CardNum);
+  cCam(cDevice *Device, int Adapter, int Frontend, const char *DevId, int Cafd, bool SoftCSA, bool FullTS);
   virtual ~cCam();
+  // CI adapter API
+  int GetCaids(int slot, unsigned short *Caids, int max);
+  void CaidsChanged(void);
+  virtual bool SetCaDescr(ca_descr_t *ca_descr, bool initial);
+  virtual bool SetCaPid(ca_pid_t *ca_pid);
+  void Stop(void);
+  void AddPrg(cPrg *prg);
+  bool HasPrg(int prg);
   // EcmHandler API
   void WriteCW(int index, unsigned char *cw, bool force);
   void SetCWIndex(int pid, int index);
   void DumpAV7110(void);
+  bool IsSoftCSA(bool live);
+  int Adapter(void) { return adapter; }
+  int Frontend(void) { return frontend; }
+  // System API
   void LogEcmStatus(const cEcmInfo *ecm, bool on);
   void AddHook(cLogHook *hook);
   bool TriggerHook(int id);
@@ -87,14 +160,40 @@ public:
   void Tune(const cChannel *channel);
   void PostTune(void);
   void SetPid(int type, int pid, bool on);
-  void Stop(void);
-  void AddPrg(cPrg *prg);
-  bool HasPrg(int prg);
-  char *CurrentKeyStr(int num);
-  //
-  bool IsSoftCSA(bool live);
+  char *CurrentKeyStr(int num, const char **id);
+  bool OwnSlot(const cCamSlot *slot) const;
+  cDeCSA *DeCSA(void) const { return decsa; }
   };
 
 void LogStatsDown(void);
 
+// ----------------------------------------------------------------
+
+#define MAX_CSA_PIDS 8192
+#define MAX_CSA_IDX  16
+
+class cDeCSA {
+private:
+  int cs;
+  unsigned char **range, *lastData;
+  unsigned char pidmap[MAX_CSA_PIDS];
+  void *keys[MAX_CSA_IDX];
+  unsigned int even_odd[MAX_CSA_IDX], flags[MAX_CSA_IDX];
+  cMutex mutex;
+  cCondVar wait;
+  cTimeMs stall;
+  bool active;
+  const char *devId;
+  //
+  bool GetKeyStruct(int idx);
+  void ResetState(void);
+public:
+  cDeCSA(const char *DevId);
+  ~cDeCSA();
+  bool Decrypt(unsigned char *data, int len, bool force);
+  bool SetDescr(ca_descr_t *ca_descr, bool initial);
+  bool SetCaPid(ca_pid_t *ca_pid);
+  void SetActive(bool on);
+  };
+
 #endif // ___CAM_H
diff --git a/data.c b/data.c
index 588b013f913eb43fc0513712d568866646012725..4e9f21e1931ff52650a2cfbf9612969e2c1f665d 100644 (file)
--- a/data.c
+++ b/data.c
@@ -544,29 +544,28 @@ void cStructLoaders::Purge(void)
 
 // -- cPid ---------------------------------------------------------------------
 
-cPid::cPid(int Pid, int Section, int Mask, int Mode)
+cPid::cPid(int Pid, int Section, int Mask)
 {
   pid=Pid;
   sct=Section;
   mask=Mask;
-  mode=Mode;
   filter=0;
 }
 
 // -- cPids --------------------------------------------------------------------
 
-void cPids::AddPid(int Pid, int Section, int Mask, int Mode)
+void cPids::AddPid(int Pid, int Section, int Mask)
 {
-  if(!HasPid(Pid,Section,Mask,Mode)) {
-    cPid *pid=new cPid(Pid,Section,Mask,Mode);
+  if(!HasPid(Pid,Section,Mask)) {
+    cPid *pid=new cPid(Pid,Section,Mask);
     Add(pid);
     }
 }
 
-bool cPids::HasPid(int Pid, int Section, int Mask, int Mode)
+bool cPids::HasPid(int Pid, int Section, int Mask)
 {
   for(cPid *pid=First(); pid; pid=Next(pid))
-    if(pid->pid==Pid && pid->sct==Section && pid->mask==Mask && pid->mode==Mode)
+    if(pid->pid==Pid && pid->sct==Section && pid->mask==Mask)
       return true;
   return false;
 }
@@ -593,6 +592,7 @@ cEcmInfo::cEcmInfo(const cEcmInfo *e)
   transponder=e->transponder;
   rewriterId=e->rewriterId;
   SetRewriter();
+  dvbAdapter=e->dvbAdapter; dvbFrontend=e->dvbFrontend;
 }
 
 cEcmInfo::cEcmInfo(const char *Name, int Pid, int CaId, int ProvId)
@@ -617,6 +617,7 @@ void cEcmInfo::Setup(void)
   prgId=grPrgId=source=transponder=-1;
   ecm_table=0x80; emmCaId=0;
   rewriter=0; rewriterId=0;
+  dvbAdapter=dvbFrontend=-1;
 }
 
 bool cEcmInfo::Compare(const cEcmInfo *e)
@@ -625,6 +626,11 @@ bool cEcmInfo::Compare(const cEcmInfo *e)
          caId==e->caId && ecm_pid==e->ecm_pid && provId==e->provId;
 }
 
+void cEcmInfo::SetDvb(int DvbAdapter, int DvbFrontend)
+{
+  dvbAdapter=DvbAdapter; dvbFrontend=DvbFrontend;
+}
+
 void cEcmInfo::SetSource(int GrPrgId, int Source, int Transponder)
 {
   grPrgId=GrPrgId; prgId=grPrgId%SIDGRP_SHIFT;
diff --git a/data.h b/data.h
index c93c9d2f0620cf02489f12e2fb4f3f62f2390c62..191d9f25525ee354e24da1d744419e6cb82634fa 100644 (file)
--- a/data.h
+++ b/data.h
@@ -202,18 +202,18 @@ public:
 
 class cPid : public cSimpleItem {
 public:
-  int pid, sct, mask, mode;
+  int pid, sct, mask;
   cPidFilter *filter;
   //
-  cPid(int Pid, int Section, int Mask, int Mode);
+  cPid(int Pid, int Section, int Mask);
   };
 
 // ----------------------------------------------------------------
 
 class cPids : public cSimpleList<cPid> {
 public:
-  void AddPid(int Pid, int Section, int Mask, int Mode=0);
-  bool HasPid(int Pid, int Section, int Mask, int Mode=0);
+  void AddPid(int Pid, int Section, int Mask);
+  bool HasPid(int Pid, int Section, int Mask);
   };
 
 // ----------------------------------------------------------------
@@ -237,6 +237,7 @@ public:
   int prgId, grPrgId, source, transponder;
   cRewriter *rewriter;
   int rewriterId;
+  int dvbAdapter, dvbFrontend;
   //
   cEcmInfo(void);
   cEcmInfo(const cEcmInfo *e);
@@ -244,6 +245,7 @@ public:
   ~cEcmInfo();
   virtual cString ToString(bool hide=false) { return ""; }
   bool Compare(const cEcmInfo *e);
+  void SetDvb(int DvbAdapter, int DvbFrontend);
   void SetSource(int GrPrgId, int Source, int Transponder);
   void SetName(const char *Name);
   void SetDataIdx(int idx);
index 2c1a5ec669a87f2adafb0a84f49521f88b9a8603..73e567e063388367acca62ca3a71442a779f66ca 100644 (file)
--- a/device.c
+++ b/device.c
@@ -24,7 +24,6 @@
 #include <sys/time.h>
 #include <dlfcn.h>
 
-#include <linux/dvb/ca.h>
 #include <vdr/channels.h>
 #include <vdr/ci.h>
 #include <vdr/dvbdevice.h>
 #include "misc.h"
 #include "log-core.h"
 
-#define MAX_CI_SLOTS      8
-
-#ifdef VDR_MAXCAID
-#define MAX_CI_SLOT_CAIDS VDR_MAXCAID
-#else
-#define MAX_CI_SLOT_CAIDS 16
-#endif
-
-// -- cCaDescr -----------------------------------------------------------------
-
-cCaDescr::cCaDescr(void)
-{
-  descr=0; len=0;
-}
-
-cCaDescr::cCaDescr(const cCaDescr &cd)
-{
-  descr=0; len=0;
-  Set(cd.descr,cd.len);
-}
-
-cCaDescr::~cCaDescr()
-{
-  Clear();
-}
-
-const unsigned char *cCaDescr::Get(int &l) const
-{
-  l=len;
-  return descr;
-}
-
-void cCaDescr::Set(const cCaDescr *d)
-{
-  Set(d->descr,d->len);
-}
-
-void cCaDescr::Set(const unsigned char *de, int l)
-{
-  Clear();
-  if(l) {
-    descr=MALLOC(unsigned char,l);
-    if(descr) {
-      memcpy(descr,de,l);
-      len=l;
-      }
-    }
-}
-
-void cCaDescr::Clear(void)
-{
-  free(descr); descr=0; len=0;
-}
-
-void cCaDescr::Join(const cCaDescr *cd, bool rev)
-{
-  if(cd->descr) {
-    int l=len+cd->len;
-    unsigned char *m=MALLOC(unsigned char,l);
-    if(m) {
-      if(!rev) {
-        if(descr) memcpy(m,descr,len);
-        memcpy(m+len,cd->descr,cd->len);
-        }
-      else {
-        memcpy(m,cd->descr,cd->len);
-        if(descr) memcpy(m+cd->len,descr,len);
-        }
-      Clear();
-      descr=m; len=l;
-      }
-    }
-}
-
-bool cCaDescr::operator== (const cCaDescr &cd) const
-{
-  return len==cd.len && (len==0 || memcmp(descr,cd.descr,len)==0);
-}
-
-cString cCaDescr::ToString(void)
-{
-  if(!descr) return "<empty>";
-  char *str=AUTOARRAY(char,len*3+8);
-  int q=sprintf(str,"%02X",descr[0]);
-  for(int i=1; i<len; i++) q+=sprintf(str+q," %02X",descr[i]);
-  return str;
-}
-
-// -- cPrg ---------------------------------------------------------------------
-
-cPrg::cPrg(void)
-{
-  Setup();
-}
-
-cPrg::cPrg(int Sid, bool IsUpdate)
-{
-  Setup();
-  sid=Sid; isUpdate=IsUpdate;
-}
-
-void cPrg::Setup(void)
-{
-  sid=-1; source=-1; transponder=-1;
-  isUpdate=pidCaDescr=false;
-}
-
-void cPrg::DumpCaDescr(int c)
-{
-  PRINTF(c,"prgca: %s",*caDescr.ToString());
-  for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
-    PRINTF(c,"pidca %04x: %s",pid->pid,*pid->caDescr.ToString());
-}
-
-bool cPrg::SimplifyCaDescr(void)
-{
-//XXX
-PRINTF(L_CORE_PIDS,"SimplyCa entry pidCa=%d",HasPidCaDescr());
-DumpCaDescr(L_CORE_PIDS);
-//XXX
-
-  if(HasPidCaDescr()) {
-    bool equal=true;
-    if(pids.Count()>1) {
-      cPrgPid *pid0=pids.First();
-      for(cPrgPid *pid1=pids.Next(pid0); pid1; pid1=pids.Next(pid1))
-        if(!(pid0->caDescr==pid1->caDescr)) { equal=false; break; }
-      }
-    if(equal) {
-      cPrgPid *pid=pids.First();
-      caDescr.Join(&pid->caDescr);
-      for(; pid; pid=pids.Next(pid)) pid->caDescr.Clear();
-      SetPidCaDescr(false);
-      }
-    }
-  if(HasPidCaDescr()) {
-    for(cPrgPid *pid=pids.First(); pid; pid=pids.Next(pid))
-      pid->caDescr.Join(&caDescr,true);
-    caDescr.Clear();
-    }
-
-//XXX
-PRINTF(L_CORE_PIDS,"SimplyCa exit pidCa=%d",HasPidCaDescr());
-DumpCaDescr(L_CORE_PIDS);
-//XXX
-
-  return HasPidCaDescr();
-}
-
-// --- cChannelCaids -----------------------------------------------------------
-
-#ifndef SASC
-
-class cChannelCaids : public cSimpleItem {
-private:
-  int prg, source, transponder;
-  int numcaids;
-  caid_t caids[MAX_CI_SLOT_CAIDS+1];
-public:
-  cChannelCaids(cChannel *channel);
-  bool IsChannel(cChannel *channel);
-  void Sort(void);
-  void Del(caid_t caid);
-  bool HasCaid(caid_t caid);
-  bool Same(cChannelCaids *ch, bool full);
-  void HistAdd(unsigned short *hist);
-  void Dump(int n);
-  const caid_t *Caids(void) { caids[numcaids]=0; return caids; }
-  int NumCaids(void) { return numcaids; }
-  int Source(void) const { return source; }
-  int Transponder(void) const { return transponder; }
-  };
-
-cChannelCaids::cChannelCaids(cChannel *channel)
-{
-  prg=channel->Sid(); source=channel->Source(); transponder=channel->Transponder();
-  numcaids=0;
-  for(const caid_t *ids=channel->Caids(); *ids; ids++)
-    if(numcaids<MAX_CI_SLOT_CAIDS) caids[numcaids++]=*ids;
-  Sort();
-}
-
-bool cChannelCaids::IsChannel(cChannel *channel)
-{
-  return prg==channel->Sid() && source==channel->Source() && transponder==channel->Transponder();
-}
-
-void cChannelCaids::Sort(void)
-{
-  caid_t tmp[MAX_CI_SLOT_CAIDS];
-  int c=0xFFFF;
-  for(int i=0; i<numcaids; i++) {
-    int d=0;
-    for(int j=0; j<numcaids; j++) if(caids[j]>d && caids[j]<c) d=caids[j];
-    tmp[i]=d; c=d;
-    }
-  memcpy(caids,tmp,sizeof(caids));
-}
-
-void cChannelCaids::Del(caid_t caid)
-{
-  for(int i=0; i<numcaids; i++)
-    if(caids[i]==caid) {
-      numcaids--; caids[i]=caids[numcaids];
-      if(numcaids>0) Sort();
-      caids[numcaids]=0;
-      break;
-      }
-}
-
-bool cChannelCaids::HasCaid(caid_t caid)
-{
-  for(int i=0; i<numcaids; i++) if(caids[i]==caid) return true;
-  return false;
-}
-
-bool cChannelCaids::Same(cChannelCaids *ch, bool full)
-{
-  if(full && (source!=ch->source || transponder!=ch->transponder)) return false;
-  if(numcaids!=ch->numcaids) return false;
-  return memcmp(caids,ch->caids,numcaids*sizeof(caid_t))==0;
-}
-
-void cChannelCaids::HistAdd(unsigned short *hist)
-{
-  for(int i=numcaids-1; i>=0; i--) hist[caids[i]]++;
-}
-
-void cChannelCaids::Dump(int n)
-{
-  LBSTART(L_CORE_CAIDS);
-  LBPUT("%d: channel %d/%x/%x",n,prg,source,transponder);
-  for(const caid_t *ids=Caids(); *ids; ids++) LBPUT(" %04x",*ids);
-  LBEND();
-}
-
-// --- cChannelList ------------------------------------------------------------
-
-class cChannelList : public cSimpleList<cChannelCaids> {
-private:
-  int n;
-public:
-  cChannelList(int N);
-  void Unique(bool full);
-  void CheckIgnore(void);
-  int Histo(void);
-  void Purge(int caid, bool fullch);
-  };
-
-cChannelList::cChannelList(int N)
-{
-  n=N;
-}
-
-void cChannelList::CheckIgnore(void)
-{
-  char *cache=MALLOC(char,0x10000);
-  if(!cache) return;
-  memset(cache,0,sizeof(char)*0x10000);
-  int cTotal=0, cHits=0;
-  for(cChannelCaids *ch=First(); ch; ch=Next(ch)) {
-    const caid_t *ids=ch->Caids();
-    while(*ids) {
-      int pri=0;
-      if(overrides.Ignore(ch->Source(),ch->Transponder(),*ids))
-        ch->Del(*ids);
-      else {
-        char c=cache[*ids];
-        if(c==0) cache[*ids]=c=(cSystems::FindIdentBySysId(*ids,false,pri) ? 1 : -1);
-        else cHits++;
-        cTotal++;
-        if(c<0) {
-          for(cChannelCaids *ch2=Next(ch); ch2; ch2=Next(ch2)) ch2->Del(*ids);
-          ch->Del(*ids);
-          }
-        else ids++;
-        }
-      }
-    }
-  free(cache);
-  PRINTF(L_CORE_CAIDS,"%d: after check",n);
-  for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(n);
-  PRINTF(L_CORE_CAIDS,"%d: check cache usage: %d requests, %d hits, %d%% hits",n,cTotal,cHits,(cTotal>0)?(cHits*100/cTotal):0);
-}
-
-void cChannelList::Unique(bool full)
-{
-  for(cChannelCaids *ch1=First(); ch1; ch1=Next(ch1)) {
-    for(cChannelCaids *ch2=Next(ch1); ch2;) {
-      if(ch1->Same(ch2,full) || ch2->NumCaids()<1) {
-        cChannelCaids *t=Next(ch2);
-        Del(ch2);
-        ch2=t;
-        }
-      else ch2=Next(ch2);
-      }
-    }
-  if(Count()==1 && First() && First()->NumCaids()<1) Del(First());
-  PRINTF(L_CORE_CAIDS,"%d: after unique (%d)",n,full);
-  for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(n);
-}
-
-int cChannelList::Histo(void)
-{
-  int h=-1;
-  unsigned short *hist=MALLOC(unsigned short,0x10000);
-  if(hist) {
-    memset(hist,0,sizeof(unsigned short)*0x10000);
-    for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->HistAdd(hist);
-    int c=0;
-    for(int i=0; i<0x10000; i++)
-      if(hist[i]>c) { h=i; c=hist[i]; }
-    free(hist);
-    }
-  else PRINTF(L_GEN_ERROR,"malloc failed in cChannelList::Histo");
-  return h;
-}
-
-void cChannelList::Purge(int caid, bool fullch)
-{
-  for(cChannelCaids *ch=First(); ch;) {
-    if(!fullch) ch->Del(caid);
-    if(ch->NumCaids()<=0 || (fullch && ch->HasCaid(caid))) {
-      cChannelCaids *t=Next(ch);
-      Del(ch);
-      ch=t;
-      }
-    else ch=Next(ch);
-    }
-  if(Count()>0) {
-    PRINTF(L_CORE_CAIDS,"%d: still left",n);
-    for(cChannelCaids *ch=First(); ch; ch=Next(ch)) ch->Dump(n);
-    }
-}
-
-// -- cCiFrame -----------------------------------------------------------------
-
-#define LEN_OFF 2
-
-class cCiFrame {
-private:
-  cRingBufferLinear *rb;
-  unsigned char *mem;
-  int len, alen, glen;
-public:
-  cCiFrame(void);
-  ~cCiFrame();
-  void SetRb(cRingBufferLinear *Rb) { rb=Rb; }
-  unsigned char *GetBuff(int l);
-  void Put(void);
-  unsigned char *Get(int &l);
-  void Del(void);
-  int Avail(void);
-  };
-
-cCiFrame::cCiFrame(void)
-{
-  rb=0; mem=0; len=alen=glen=0;
-}
-
-cCiFrame::~cCiFrame()
-{
-  free(mem);
-}
-
-unsigned char *cCiFrame::GetBuff(int l)
-{
-  if(!mem || l>alen) {
-    free(mem); mem=0; alen=0;
-    mem=MALLOC(unsigned char,l+LEN_OFF);
-    if(mem) alen=l;
-    }
-  len=l;
-  if(!mem) {
-    PRINTF(L_GEN_DEBUG,"internal: ci-frame alloc failed");
-    return 0;
-    }
-  return mem+LEN_OFF;
-}
-
-void cCiFrame::Put(void)
-{
-  if(rb && mem) {
-    *((short *)mem)=len;
-    rb->Put(mem,len+LEN_OFF);
-    }
-}
-
-unsigned char *cCiFrame::Get(int &l)
-{
-  if(rb) {
-    int c;
-    unsigned char *data=rb->Get(c);
-    if(data) {
-      if(c>LEN_OFF) {
-        int s=*((short *)data);
-        if(c>=s+LEN_OFF) {
-          l=glen=s;
-          return data+LEN_OFF;
-          }
-        }
-      LDUMP(L_GEN_DEBUG,data,c,"internal: ci rb frame sync got=%d avail=%d -",c,rb->Available());
-      rb->Clear();
-      }
-    }
-  return 0;
-}
-
-int cCiFrame::Avail(void)
-{
-  return rb ? rb->Available() : 0;
-}
-
-void cCiFrame::Del(void)
-{
-  if(rb && glen) {
-    rb->Del(glen+LEN_OFF);
-    glen=0;
-    }
-}
-
-// -- cScCiAdapter -------------------------------------------------------------
-
-#define CAID_TIME      300000 // time between caid scans
-#define TRIGGER_TIME    10000 // min. time between caid scan trigger
-
-#define TDPU_SIZE_INDICATOR 0x80
-
-struct TPDU {
-  unsigned char slot;
-  unsigned char tcid;
-  unsigned char tag;
-  unsigned char len;
-  unsigned char data[1];
-  };
-
-class cScCamSlot;
-
-class cScCiAdapter : public cCiAdapter {
-private:
-  cDevice *device;
-  cCam *cam;
-  cMutex ciMutex;
-  int cardIndex;
-  cRingBufferLinear *rb;
-  cScCamSlot *slots[MAX_CI_SLOTS];
-  cCiFrame frame;
-  //
-  cTimeMs caidTimer, triggerTimer;
-  int version[MAX_CI_SLOTS];
-  caid_t caids[MAX_CI_SLOTS][MAX_CI_SLOT_CAIDS+1];
-  int tcid;
-  bool rebuildcaids;
-  //
-  cTimeMs readTimer, writeTimer;
-  //
-  void BuildCaids(bool force);
-protected:
-  virtual int Read(unsigned char *Buffer, int MaxLength);
-  virtual void Write(const unsigned char *Buffer, int Length);
-  virtual bool Reset(int Slot);
-  virtual eModuleStatus ModuleStatus(int Slot);
-  virtual bool Assign(cDevice *Device, bool Query=false);
-public:
-  cScCiAdapter(cDevice *Device, int CardIndex, cCam *Cam);
-  ~cScCiAdapter();
-  void CamStop(void);
-  void CamAddPrg(cPrg *prg);
-  bool CamSoftCSA(void);
-  int GetCaids(int slot, unsigned short *Caids, int max);
-  void CaidsChanged(void);
-  };
-
-// -- cScCamSlot ---------------------------------------------------------------
-
-#define SLOT_CAID_CHECK 10000
-#define SLOT_RESET_TIME 600
-
-class cScCamSlot : public cCamSlot {
-private:
-  cScCiAdapter *ciadapter;
-  unsigned short caids[MAX_CI_SLOT_CAIDS+1];
-  int slot, cardIndex, version;
-  cTimeMs checkTimer;
-  bool reset, doReply;
-  cTimeMs resetTimer;
-  eModuleStatus lastStatus;
-  cRingBufferLinear rb;
-  cCiFrame frame;
-  //
-  int GetLength(const unsigned char * &data);
-  int LengthSize(int n);
-  void SetSize(int n, unsigned char * &p);
-  void CaInfo(int tcid, int cid);
-  bool Check(void);
-public:
-  cScCamSlot(cScCiAdapter *ca, int CardIndex, int Slot);
-  void Process(const unsigned char *data, int len);
-  eModuleStatus Status(void);
-  bool Reset(bool log=true);
-  cCiFrame *Frame(void) { return &frame; }
-  };
-
-cScCamSlot::cScCamSlot(cScCiAdapter *ca, int CardIndex, int Slot)
-:cCamSlot(ca)
-,checkTimer(-SLOT_CAID_CHECK-1000)
-,rb(KILOBYTE(4),5+LEN_OFF,false,"SC-CI slot answer")
-{
-  ciadapter=ca; cardIndex=CardIndex; slot=Slot;
-  version=0; caids[0]=0; doReply=false; lastStatus=msReset;
-  frame.SetRb(&rb);
-  Reset(false);
-}
-
-eModuleStatus cScCamSlot::Status(void)
-{
-  eModuleStatus status;
-  if(reset) { 
-    status=msReset;
-    if(resetTimer.TimedOut()) reset=false;
-    }
-  else if(caids[0]) status=msReady;
-  else {
-    status=msPresent; //msNone;
-    Check();
-    }
-  if(status!=lastStatus) {
-    static const char *stext[] = { "none","reset","present","ready" };
-    PRINTF(L_CORE_CI,"%d.%d: status '%s'",cardIndex,slot,stext[status]);
-    lastStatus=status;
-    }
-  return status;
-}
-
-bool cScCamSlot::Reset(bool log)
-{
-  reset=true; resetTimer.Set(SLOT_RESET_TIME);
-  rb.Clear();
-  if(log) PRINTF(L_CORE_CI,"%d.%d: reset",cardIndex,slot);
-  return true;
-}
-
-bool cScCamSlot::Check(void)
-{
-  bool res=false;
-  bool dr=ciadapter->CamSoftCSA() || ScSetup.ConcurrentFF>0;
-  if(dr!=doReply && !IsDecrypting()) {
-    PRINTF(L_CORE_CI,"%d.%d: doReply changed, reset triggered",cardIndex,slot);
-    Reset(false);
-    doReply=dr;
-    }
-  if(checkTimer.TimedOut()) {
-    if(version!=ciadapter->GetCaids(slot,0,0)) {
-      version=ciadapter->GetCaids(slot,caids,MAX_CI_SLOT_CAIDS);
-      PRINTF(L_CORE_CI,"%d.%d: now using CAIDs version %d",cardIndex,slot,version);
-      res=true;
-      }
-    checkTimer.Set(SLOT_CAID_CHECK);
-    }
-  return res;
-}
-
-int cScCamSlot::GetLength(const unsigned char * &data)
-{
-  int len=*data++;
-  if(len&TDPU_SIZE_INDICATOR) {
-    int i;
-    for(i=len&~TDPU_SIZE_INDICATOR, len=0; i>0; i--) len=(len<<8) + *data++;
-    }
-  return len;
-}
-
-int cScCamSlot::LengthSize(int n)
-{
-  return n<TDPU_SIZE_INDICATOR?1:3;
-}
-
-void cScCamSlot::SetSize(int n, unsigned char * &p)
-{
-  if(n<TDPU_SIZE_INDICATOR) *p++=n;
-  else { *p++=2|TDPU_SIZE_INDICATOR; *p++=n>>8; *p++=n&0xFF; }
-}
-
-void cScCamSlot::CaInfo(int tcid, int cid)
-{
-  int cn=0;
-  for(int i=0; caids[i]; i++) cn+=2;
-  int n=cn+8+LengthSize(cn);
-  unsigned char *p;
-  if(!(p=frame.GetBuff(n+1+LengthSize(n)))) return;
-  *p++=0xa0;
-  SetSize(n,p);
-  *p++=tcid;
-  *p++=0x90;
-  *p++=0x02; *p++=cid>>8; *p++=cid&0xff;
-  *p++=0x9f; *p++=0x80;   *p++=0x31; // AOT_CA_INFO
-  SetSize(cn,p);
-  for(int i=0; caids[i]; i++) { *p++=caids[i]>>8; *p++=caids[i]&0xff; }
-  frame.Put();
-  PRINTF(L_CORE_CI,"%d.%d sending CA info",cardIndex,slot);
-}
-
-void cScCamSlot::Process(const unsigned char *data, int len)
-{
-  const unsigned char *save=data;
-  data+=3;
-  int dlen=GetLength(data);
-  if(dlen>len-(data-save)) {
-    PRINTF(L_CORE_CI,"%d.%d TDPU length exceeds data length",cardIndex,slot);
-    dlen=len-(data-save);
-    }
-  int tcid=data[0];
-
-  if(Check()) CaInfo(tcid,0x01);
-
-  if(dlen<8 || data[1]!=0x90) return;
-  int cid=(data[3]<<8)+data[4];
-  int tag=(data[5]<<16)+(data[6]<<8)+data[7];
-  data+=8;
-  dlen=GetLength(data);
-  if(dlen>len-(data-save)) {
-    PRINTF(L_CORE_CI,"%d.%d tag length exceeds data length",cardIndex,slot);
-    dlen=len-(data-save);
-    }
-  switch(tag) {
-    case 0x9f8030: // AOT_CA_INFO_ENQ
-      CaInfo(tcid,cid);
-      break;
-    
-    case 0x9f8032: // AOT_CA_PMT
-      if(dlen>=6) {
-        int ca_lm=data[0];
-        int ci_cmd=-1;
-        cPrg *prg=new cPrg((data[1]<<8)+data[2],ca_lm==5);
-        int ilen=(data[4]<<8)+data[5];
-        LBSTARTF(L_CORE_CI);
-        LBPUT("%d.%d CA_PMT decoding len=%x lm=%x prg=%d len=%x",cardIndex,slot,dlen,ca_lm,(data[1]<<8)+data[2],ilen);
-        data+=6; dlen-=6;
-        LBPUT("/%x",dlen);
-        if(ilen>0 && dlen>=ilen) {
-          ci_cmd=data[0];
-          if(ilen>1)
-            prg->caDescr.Set(&data[1],ilen-1);
-          LBPUT(" ci_cmd(G)=%02x",ci_cmd);
-          }
-        data+=ilen; dlen-=ilen;
-        while(dlen>=5) {
-          cPrgPid *pid=new cPrgPid(data[0],(data[1]<<8)+data[2]);
-          prg->pids.Add(pid);
-          ilen=(data[3]<<8)+data[4];
-          LBPUT(" pid=%d,%x len=%x",data[0],(data[1]<<8)+data[2],ilen);
-          data+=5; dlen-=5;
-          LBPUT("/%x",dlen);
-          if(ilen>0 && dlen>=ilen) {
-            ci_cmd=data[0];
-            if(ilen>1) {
-              pid->caDescr.Set(&data[1],ilen-1);
-              prg->SetPidCaDescr(true);
-              }
-            LBPUT(" ci_cmd(S)=%x",ci_cmd);
-            }
-          data+=ilen; dlen-=ilen;
-          }
-        LBEND();
-        PRINTF(L_CORE_CI,"%d.%d got CA pmt ciCmd=%d caLm=%d",cardIndex,slot,ci_cmd,ca_lm);
-        if(doReply && (ci_cmd==0x03 || (ci_cmd==0x01 && ca_lm==0x03))) {
-          unsigned char *b;
-          if((b=frame.GetBuff(4+11))) {
-            b[0]=0xa0; b[2]=tcid;
-            b[3]=0x90;
-            b[4]=0x02; b[5]=cid<<8; b[6]=cid&0xff;
-            b[7]=0x9f; b[8]=0x80; b[9]=0x33; // AOT_CA_PMT_REPLY
-            b[11]=prg->sid<<8;
-            b[12]=prg->sid&0xff;
-            b[13]=0x00;
-            b[14]=0x81;        // CA_ENABLE
-            b[10]=4; b[1]=4+9;
-            frame.Put();
-            PRINTF(L_CORE_CI,"%d.%d answer to query",cardIndex,slot);
-            }
-          }
-        if(prg->sid!=0) {
-          if(ci_cmd==0x04) {
-            PRINTF(L_CORE_CI,"%d.%d stop decrypt",cardIndex,slot);
-            ciadapter->CamStop();
-            }
-          if(ci_cmd==0x01 || (ci_cmd==-1 && (ca_lm==0x04 || ca_lm==0x05))) {
-            PRINTF(L_CORE_CI,"%d.%d set CAM decrypt (prg %d)",cardIndex,slot,prg->sid);
-            ciadapter->CamAddPrg(prg);
-            }
-          }
-        delete prg;
-        }
-      break;
-    }
-}
-
-// -- cScCiAdapter -------------------------------------------------------------
-
-cScCiAdapter::cScCiAdapter(cDevice *Device, int CardIndex, cCam *Cam)
-{
-  device=Device; cardIndex=CardIndex; cam=Cam;
-  tcid=0; rebuildcaids=false;
-  memset(version,0,sizeof(version));
-  memset(slots,0,sizeof(slots));
-  SetDescription("SC-CI adapter on device %d",cardIndex);
-  rb=new cRingBufferLinear(KILOBYTE(8),6+LEN_OFF,false,"SC-CI adapter read");
-  if(rb) {
-    rb->SetTimeouts(0,CAM_READ_TIMEOUT);
-    frame.SetRb(rb);
-/*
-    bool spare=true;
-    for(int i=0; i<MAX_CI_SLOTS; i++) {
-      if(GetCaids(i,0,0)<=0) {
-        if(!spare) break;
-        spare=false;
-        }
-      slots[i]=new cScCamSlot(this,cardIndex,i);
-      }
-*/
-    BuildCaids(true);
-    slots[0]=new cScCamSlot(this,cardIndex,0);
-    Start();
-    }
-  else PRINTF(L_GEN_ERROR,"failed to create ringbuffer for SC-CI adapter %d.",cardIndex);
-}
-
-cScCiAdapter::~cScCiAdapter()
-{
-  Cancel(3);
-  ciMutex.Lock();
-  delete rb; rb=0;
-  ciMutex.Unlock();
-}
-
-void cScCiAdapter::CamStop(void)
-{
-  if(cam) cam->Stop();
-}
-
-void cScCiAdapter::CamAddPrg(cPrg *prg)
-{
-  if(cam) cam->AddPrg(prg);
-}
-
-bool cScCiAdapter::CamSoftCSA(void)
-{
-  return cam && cam->IsSoftCSA(false);
-}
-
-int cScCiAdapter::GetCaids(int slot, unsigned short *Caids, int max)
-{
-  BuildCaids(false);
-  cMutexLock lock(&ciMutex);
-  if(Caids) {
-    int i;
-    for(i=0; i<MAX_CI_SLOT_CAIDS && i<max && caids[i]; i++) Caids[i]=caids[slot][i];
-    Caids[i]=0;
-    }
-  return version[slot];
-}
-
-void cScCiAdapter::CaidsChanged(void)
-{
-  rebuildcaids=true;
-}
-
-void cScCiAdapter::BuildCaids(bool force)
-{
-  if(caidTimer.TimedOut() || force || (rebuildcaids && triggerTimer.TimedOut())) {
-    PRINTF(L_CORE_CAIDS,"%d: building caid lists",cardIndex);
-    cChannelList list(cardIndex);
-    Channels.Lock(false);
-    for(cChannel *channel=Channels.First(); channel; channel=Channels.Next(channel)) {
-      if(!channel->GroupSep() && channel->Ca()>=CA_ENCRYPTED_MIN && device->ProvidesTransponder(channel)) {
-        cChannelCaids *ch=new cChannelCaids(channel);
-        if(ch) list.Add(ch);
-        }
-      }
-    Channels.Unlock();
-    list.Unique(true);
-    list.CheckIgnore();
-    list.Unique(false);
-
-    int n=0, h;
-    caid_t c[MAX_CI_SLOT_CAIDS+1];
-    memset(c,0,sizeof(c));
-    do {
-      if((h=list.Histo())<0) break;
-      c[n++]=h;
-      LBSTART(L_CORE_CAIDS);
-      LBPUT("%d: added %04x caids now",cardIndex,h); for(int i=0; i<n; i++) LBPUT(" %04x",c[i]);
-      LBEND();
-      list.Purge(h,false);
-      } while(n<MAX_CI_SLOT_CAIDS && list.Count()>0);
-    c[n]=0;
-    if(n==0) PRINTF(L_CORE_CI,"no active CAIDs");
-    else if(list.Count()>0) PRINTF(L_GEN_ERROR,"too many CAIDs. You should ignore some CAIDs.");
-
-    ciMutex.Lock();
-    if((version[0]==0 && c[0]!=0) || memcmp(caids[0],c,sizeof(caids[0]))) {
-      memcpy(caids[0],c,sizeof(caids[0]));
-      version[0]++;
-      if(version[0]>0) {
-        LBSTART(L_CORE_CI);
-        LBPUT("card %d, slot %d (v=%2d) caids:",cardIndex,0,version[0]);
-        for(int i=0; caids[0][i]; i++) LBPUT(" %04x",caids[0][i]);
-        LBEND();
-        }
-      }
-    ciMutex.Unlock();
-
-    caidTimer.Set(CAID_TIME);
-    triggerTimer.Set(TRIGGER_TIME);
-    rebuildcaids=false;
-    }
-}
-
-int cScCiAdapter::Read(unsigned char *Buffer, int MaxLength)
-{
-  cMutexLock lock(&ciMutex);
-  if(cam && rb && Buffer && MaxLength>0) {
-    int s;
-    unsigned char *data=frame.Get(s);
-    if(data) {
-      if(s<=MaxLength) memcpy(Buffer,data,s);
-      else PRINTF(L_GEN_DEBUG,"internal: sc-ci %d rb frame size exceeded %d",cardIndex,s);
-      frame.Del();
-      if(Buffer[2]!=0x80 || LOG(L_CORE_CIFULL)) {
-        LDUMP(L_CORE_CI,Buffer,s,"%d.%d <-",cardIndex,Buffer[0]);
-        readTimer.Set();
-        }
-      return s;
-      }
-    }
-  else cCondWait::SleepMs(CAM_READ_TIMEOUT);
-  if(LOG(L_CORE_CIFULL) && readTimer.Elapsed()>2000) {
-    PRINTF(L_CORE_CIFULL,"%d: read heartbeat",cardIndex);
-    readTimer.Set();
-    }
-  return 0;
-}
-
-#define TPDU(data,slot)   do { unsigned char *_d=(data); _d[0]=(slot); _d[1]=tcid; } while(0)
-#define TAG(data,tag,len) do { unsigned char *_d=(data); _d[0]=(tag); _d[1]=(len); } while(0)
-#define SB_TAG(data,sb)   do { unsigned char *_d=(data); _d[0]=0x80; _d[1]=0x02; _d[2]=tcid; _d[3]=(sb); } while(0)
-
-void cScCiAdapter::Write(const unsigned char *buff, int len)
-{
-  cMutexLock lock(&ciMutex);
-  if(cam && buff && len>=5) {
-    struct TPDU *tpdu=(struct TPDU *)buff;
-    int slot=tpdu->slot;
-    cCiFrame *slotframe=slots[slot]->Frame();
-    if(buff[2]!=0xA0 || buff[3]>0x01 || LOG(L_CORE_CIFULL))
-      LDUMP(L_CORE_CI,buff,len,"%d.%d ->",cardIndex,slot);
-    if(slots[slot]) {
-      switch(tpdu->tag) {
-        case 0x81: // T_RCV
-          {
-          int s;
-          unsigned char *d=slotframe->Get(s);
-          if(d) {
-            unsigned char *b;
-            if((b=frame.GetBuff(s+6))) {
-              TPDU(b,slot);
-              memcpy(b+2,d,s);
-              slotframe->Del(); // delete from rb before Avail()
-              SB_TAG(b+2+s,slotframe->Avail()>0 ? 0x80:0x00);
-              frame.Put();
-              }
-            else slotframe->Del();
-            }
-          break;
-          }
-        case 0x82: // T_CREATE_TC
-          {
-          tcid=tpdu->data[0];
-          unsigned char *b;
-          static const unsigned char reqCAS[] = { 0xA0,0x07,0x01,0x91,0x04,0x00,0x03,0x00,0x41 };
-          if((b=slotframe->GetBuff(sizeof(reqCAS)))) {
-            memcpy(b,reqCAS,sizeof(reqCAS));
-            b[2]=tcid;
-            slotframe->Put();
-            }
-          if((b=frame.GetBuff(9))) {
-            TPDU(b,slot);
-            TAG(&b[2],0x83,0x01); b[4]=tcid;
-            SB_TAG(&b[5],slotframe->Avail()>0 ? 0x80:0x00);
-            frame.Put();
-            }
-          break;
-          }
-        case 0xA0: // T_DATA_LAST
-          {
-          slots[slot]->Process(buff,len);
-          unsigned char *b;
-          if((b=frame.GetBuff(6))) {
-            TPDU(b,slot);
-            SB_TAG(&b[2],slotframe->Avail()>0 ? 0x80:0x00);
-            frame.Put();
-            }
-          break;
-          }
-        }
-      }
-    }
-  else PRINTF(L_CORE_CIFULL,"%d: short write (cam=%d buff=%d len=%d)",cardIndex,cam!=0,buff!=0,len);
-}
-
-bool cScCiAdapter::Reset(int Slot)
-{
-  cMutexLock lock(&ciMutex);
-  PRINTF(L_CORE_CI,"%d: reset of slot %d requested",cardIndex,Slot);
-  return slots[Slot] ? slots[Slot]->Reset():false;
-}
-
-eModuleStatus cScCiAdapter::ModuleStatus(int Slot)
-{
-  cMutexLock lock(&ciMutex);
-  bool enable=ScSetup.CapCheck(cardIndex);
-  if(!enable) CamStop();
-  return (enable && cam && slots[Slot]) ? slots[Slot]->Status():msNone;
-}
-
-bool cScCiAdapter::Assign(cDevice *Device, bool Query)
-{
-  return Device ? (Device==device) : true;
-}
-
-// -- cDeCSA -------------------------------------------------------------------
-
-#define MAX_CSA_PIDS 8192
-#define MAX_CSA_IDX  16
-#define MAX_STALL_MS 70
-
-#define MAX_REL_WAIT 100 // time to wait if key in used on set
-#define MAX_KEY_WAIT 500 // time to wait if key not ready on change
-
-#define FL_EVEN_GOOD 1
-#define FL_ODD_GOOD  2
-#define FL_ACTIVITY  4
-
-class cDeCSA {
-private:
-  int cs;
-  unsigned char **range, *lastData;
-  unsigned char pidmap[MAX_CSA_PIDS];
-  void *keys[MAX_CSA_IDX];
-  unsigned int even_odd[MAX_CSA_IDX], flags[MAX_CSA_IDX];
-  cMutex mutex;
-  cCondVar wait;
-  cTimeMs stall;
-  bool active;
-  int cardindex;
-  //
-  bool GetKeyStruct(int idx);
-  void ResetState(void);
-public:
-  cDeCSA(int CardIndex);
-  ~cDeCSA();
-  bool Decrypt(unsigned char *data, int len, bool force);
-  bool SetDescr(ca_descr_t *ca_descr, bool initial);
-  bool SetCaPid(ca_pid_t *ca_pid);
-  void SetActive(bool on);
-  };
-
-cDeCSA::cDeCSA(int CardIndex)
-:stall(MAX_STALL_MS)
-{
-  cardindex=CardIndex;
-  cs=get_suggested_cluster_size();
-  PRINTF(L_CORE_CSA,"%d: clustersize=%d rangesize=%d",cardindex,cs,cs*2+5);
-  range=MALLOC(unsigned char *,(cs*2+5));
-  memset(keys,0,sizeof(keys));
-  memset(pidmap,0,sizeof(pidmap));
-  ResetState();
-}
-
-cDeCSA::~cDeCSA()
-{
-  for(int i=0; i<MAX_CSA_IDX; i++)
-    if(keys[i]) free_key_struct(keys[i]);
-  free(range);
-}
-
-void cDeCSA::ResetState(void)
-{
-  PRINTF(L_CORE_CSA,"%d: reset state",cardindex);
-  memset(even_odd,0,sizeof(even_odd));
-  memset(flags,0,sizeof(flags));
-  lastData=0;
-}
-
-void cDeCSA::SetActive(bool on)
-{
-  if(!on && active) ResetState();
-  active=on;
-  PRINTF(L_CORE_CSA,"%d: set active %s",cardindex,active?"on":"off");
-}
-
-bool cDeCSA::GetKeyStruct(int idx)
-{
-  if(!keys[idx]) keys[idx]=get_key_struct();
-  return keys[idx]!=0;
-}
-
-bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
-{
-  cMutexLock lock(&mutex);
-  int idx=ca_descr->index;
-  if(idx<MAX_CSA_IDX && GetKeyStruct(idx)) {
-    if(!initial && active && ca_descr->parity==(even_odd[idx]&0x40)>>6) {
-      if(flags[idx] & (ca_descr->parity?FL_ODD_GOOD:FL_EVEN_GOOD)) {
-        PRINTF(L_CORE_CSA,"%d.%d: %s key in use (%d ms)",cardindex,idx,ca_descr->parity?"odd":"even",MAX_REL_WAIT);
-        if(wait.TimedWait(mutex,MAX_REL_WAIT)) PRINTF(L_CORE_CSA,"%d.%d: successfully waited for release",cardindex,idx);
-        else PRINTF(L_CORE_CSA,"%d.%d: timed out. setting anyways",cardindex,idx);
-        }
-      else PRINTF(L_CORE_CSA,"%d.%d: late key set...",cardindex,idx);
-      }
-    LDUMP(L_CORE_CSA,ca_descr->cw,8,"%d.%d: %4s key set",cardindex,idx,ca_descr->parity?"odd":"even");
-    if(ca_descr->parity==0) {
-      set_even_control_word(keys[idx],ca_descr->cw);
-      if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_EVEN_GOOD|FL_ACTIVITY;
-      else PRINTF(L_CORE_CSA,"%d.%d: zero even CW",cardindex,idx);
-      wait.Broadcast();
-      }
-    else {
-      set_odd_control_word(keys[idx],ca_descr->cw);
-      if(!CheckNull(ca_descr->cw,8)) flags[idx]|=FL_ODD_GOOD|FL_ACTIVITY;
-      else PRINTF(L_CORE_CSA,"%d.%d: zero odd CW",cardindex,idx);
-      wait.Broadcast();
-      }
-    }
-  return true;
-}
-
-bool cDeCSA::SetCaPid(ca_pid_t *ca_pid)
-{
-  cMutexLock lock(&mutex);
-  if(ca_pid->index<MAX_CSA_IDX && ca_pid->pid<MAX_CSA_PIDS) {
-    pidmap[ca_pid->pid]=ca_pid->index;
-    PRINTF(L_CORE_CSA,"%d.%d: set pid %04x",cardindex,ca_pid->index,ca_pid->pid);
-    }
-  return true;
-}
-
-bool cDeCSA::Decrypt(unsigned char *data, int len, bool force)
-{
-  cMutexLock lock(&mutex);
-  int r=-2, ccs=0, currIdx=-1;
-  bool newRange=true;
-  range[0]=0;
-  len-=(TS_SIZE-1);
-  int l;
-  for(l=0; l<len; l+=TS_SIZE) {
-    if(data[l]!=TS_SYNC_BYTE) {       // let higher level cope with that
-      PRINTF(L_CORE_CSA,"%d: garbage in TS buffer",cardindex);
-      if(ccs) force=true;             // prevent buffer stall
-      break;
-      }
-    unsigned int ev_od=data[l+3]&0xC0;
-    if(ev_od==0x80 || ev_od==0xC0) { // encrypted
-      int idx=pidmap[((data[l+1]<<8)+data[l+2])&(MAX_CSA_PIDS-1)];
-      if(currIdx<0 || idx==currIdx) { // same or no index
-        currIdx=idx;
-        if(ccs==0 && ev_od!=even_odd[idx]) {
-          even_odd[idx]=ev_od;
-          wait.Broadcast();
-          PRINTF(L_CORE_CSA,"%d.%d: change to %s key",cardindex,idx,(ev_od&0x40)?"odd":"even");
-          bool doWait=false;
-          if(ev_od&0x40) {
-            flags[idx]&=~FL_EVEN_GOOD;
-            if(!(flags[idx]&FL_ODD_GOOD)) doWait=true;
-            }
-          else {
-            flags[idx]&=~FL_ODD_GOOD;
-            if(!(flags[idx]&FL_EVEN_GOOD)) doWait=true;
-            }
-          if(doWait) {
-            PRINTF(L_CORE_CSA,"%d.%d: %s key not ready (%d ms)",cardindex,idx,(ev_od&0x40)?"odd":"even",MAX_KEY_WAIT);
-            if(flags[idx]&FL_ACTIVITY) {
-              flags[idx]&=~FL_ACTIVITY;
-              if(wait.TimedWait(mutex,MAX_KEY_WAIT)) PRINTF(L_CORE_CSA,"%d.%d: successfully waited for key",cardindex,idx);
-              else PRINTF(L_CORE_CSA,"%d.%d: timed out. proceeding anyways",cardindex,idx);
-              }
-            else PRINTF(L_CORE_CSA,"%d.%d: not active. wait skipped",cardindex,idx);
-            }
-          }
-        if(newRange) {
-          r+=2; newRange=false;
-          range[r]=&data[l];
-          range[r+2]=0;
-          }
-        range[r+1]=&data[l+TS_SIZE];
-        if(++ccs>=cs) break;
-        }
-      else newRange=true;             // other index, create hole
-      }
-    else {                            // unencrypted
-      // nothing, we don't create holes for unencrypted packets
-      }
-    }
-  int scanTS=l/TS_SIZE;
-  int stallP=ccs*100/scanTS;
-
-  LBSTART(L_CORE_CSAVERB);
-  LBPUT("%d: %s-%d-%d : %d-%d-%d stall=%d :: ",
-        cardindex,data==lastData?"SAME":"MOVE",(len+(TS_SIZE-1))/TS_SIZE,force,
-        currIdx,ccs,scanTS,stallP);
-  for(int l=0; l<len; l+=TS_SIZE) {
-    if(data[l]!=TS_SYNC_BYTE) break;
-    unsigned int ev_od=data[l+3]&0xC0;
-    if(ev_od&0x80) {
-      int pid=(data[l+1]<<8)+data[l+2];
-      int idx=pidmap[pid&(MAX_CSA_PIDS-1)];
-      LBPUT("%s/%x/%d ",(ev_od&0x40)?"o":"e",pid,idx);
-      }
-    else {
-      LBPUT("*/%x ",(data[l+1]<<8)+data[l+2]);
-      }
-    }
-  LBEND();
-
-  if(r>=0 && ccs<cs && !force) {
-    if(lastData==data && stall.TimedOut()) {
-      PRINTF(L_CORE_CSAVERB,"%d: stall timeout -> forced",cardindex);
-      force=true;
-      }
-    else if(stallP<=10 && scanTS>=cs) {
-      PRINTF(L_CORE_CSAVERB,"%d: flow factor stall -> forced",cardindex);
-      force=true;
-      }
-    }
-  lastData=data;
-
-  if(r>=0) {                          // we have some range
-    if(ccs>=cs || force) {
-      if(GetKeyStruct(currIdx)) {
-        int n=decrypt_packets(keys[currIdx],range);
-        PRINTF(L_CORE_CSAVERB,"%d.%d: decrypting ccs=%3d cs=%3d %s -> %3d decrypted",cardindex,currIdx,ccs,cs,ccs>=cs?"OK ":"INC",n);
-        if(n>0) {
-          stall.Set(MAX_STALL_MS);
-          return true;
-          }
-        }
-      }
-    else PRINTF(L_CORE_CSAVERB,"%d.%d: incomplete ccs=%3d cs=%3d",cardindex,currIdx,ccs,cs);
-    }
-  return false;
-}
-
 // -- cDeCsaTSBuffer -----------------------------------------------------------
 
 class cDeCsaTSBuffer : public cThread {
@@ -1290,8 +137,6 @@ uchar *cDeCsaTSBuffer::Get(void)
   return NULL;
 }
 
-#endif //SASC
-
 // --- cScDeviceProbe ----------------------------------------------------------
 
 #define DEV_DVB_ADAPTER  "/dev/dvb/adapter"
@@ -1358,8 +203,10 @@ static int *vdr_nci=0, *vdr_ud=0, vdr_save_ud;
 void cScDevices::OnPluginLoad(void)
 {
 #if APIVERSNUM >= 10711
+  PRINTF(L_GEN_DEBUG,"using new 1.7.11+ capture code");
   cScDeviceProbe::Install();
 #else
+  PRINTF(L_GEN_DEBUG,"using old pre1.7.11 capture code");
 /*
   This is an extremly ugly hack to access VDRs device scan parameters, which are
   protected in this context. Heavily dependant on the actual symbol names
@@ -1490,15 +337,17 @@ cScDevice::cScDevice(int Adapter, int Frontend, int cafd)
 :cDvbDevice(Adapter)
 #endif
 {
-#ifndef SASC
-  decsa=0; tsBuffer=0; cam=0; fullts=false;
-  ciadapter=0; hwciadapter=0;
+  tsBuffer=0; softcsa=fullts=false;
+  cam=0; hwciadapter=0;
   fd_ca=cafd; fd_ca2=dup(fd_ca); fd_dvr=-1;
-  softcsa=(fd_ca<0);
-#else
-  softcsa=fullts=false;
+#ifdef SASC
   cam=new cCam(this,Adapter);
 #endif // !SASC
+#if APIVERSNUM >= 10711
+  snprintf(devId,sizeof(devId),"%d/%d",Adapter,FrontEnd);
+#else
+  snprintf(devId,sizeof(devId),"%d",Adapter);
+#endif
 }
 
 cScDevice::~cScDevice()
@@ -1507,7 +356,6 @@ cScDevice::~cScDevice()
   DetachAllReceivers();
   Cancel(3);
   EarlyShutdown();
-  delete decsa;
   if(fd_ca>=0) close(fd_ca);
   if(fd_ca2>=0) close(fd_ca2);
 #else
@@ -1520,10 +368,8 @@ cScDevice::~cScDevice()
 void cScDevice::EarlyShutdown(void)
 {
   SetCamSlot(0);
-  delete ciadapter; ciadapter=0;
-  delete hwciadapter; hwciadapter=0;
-  if(cam) cam->Stop();
   delete cam; cam=0;
+  delete hwciadapter; hwciadapter=0;
 }
 
 void cScDevice::LateInit(void)
@@ -1531,35 +377,33 @@ void cScDevice::LateInit(void)
   int n=CardIndex();
   if(DeviceNumber()!=n)
     PRINTF(L_GEN_ERROR,"CardIndex - DeviceNumber mismatch! Put SC plugin first on VDR commandline!");
+  softcsa=(fd_ca<0);
   if(softcsa) {
-    if(HasDecoder()) PRINTF(L_GEN_ERROR,"Card %d is a full-featured card but no ca device found!",n);
+    if(HasDecoder()) PRINTF(L_GEN_ERROR,"Card %s is a full-featured card but no ca device found!",devId);
     }
   else if(cScDevices::ForceBudget(n)) {
-    PRINTF(L_GEN_INFO,"Budget mode forced on card %d",n);
+    PRINTF(L_GEN_INFO,"Budget mode forced on card %s",devId);
     softcsa=true;
     }
-  
-  if(fd_ca2>=0) hwciadapter=cDvbCiAdapter::CreateCiAdapter(this,fd_ca2);
-  cam=new cCam(this,n);
-  ciadapter=new cScCiAdapter(this,n,cam);
   if(softcsa) {
-    decsa=new cDeCSA(n);
     if(IsPrimaryDevice() && HasDecoder()) {
-      PRINTF(L_GEN_INFO,"Enabling hybrid full-ts mode on card %d",n);
+      PRINTF(L_GEN_INFO,"Enabling hybrid full-ts mode on card %s",devId);
       fullts=true;
       }
-    else PRINTF(L_GEN_INFO,"Using software decryption on card %d",n);
+    else PRINTF(L_GEN_INFO,"Using software decryption on card %s",devId);
     }
+  if(fd_ca2>=0) hwciadapter=cDvbCiAdapter::CreateCiAdapter(this,fd_ca2);
+  cam=new cCam(this,DVB_DEV_SPEC,devId,fd_ca,softcsa,fullts);
 }
 
 bool cScDevice::HasCi(void)
 {
-  return ciadapter || hwciadapter;
+  return cam || hwciadapter;
 }
 
 bool cScDevice::Ready(void)
 {
-  return (ciadapter   ? ciadapter->Ready():true) &&
+  return (cam         ? cam->Ready():true) &&
          (hwciadapter ? hwciadapter->Ready():true);
 }
 
@@ -1582,7 +426,7 @@ bool cScDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 
 bool cScDevice::ScActive(void)
 {
-  return dynamic_cast<cScCamSlot *>(CamSlot())!=0;
+  return cam && cam->OwnSlot(CamSlot());
 }
 
 bool cScDevice::OpenDvr(void)
@@ -1590,6 +434,7 @@ bool cScDevice::OpenDvr(void)
   CloseDvr();
   fd_dvr=cScDevices::DvbOpen(DEV_DVB_DVR,DVB_DEV_SPEC,O_RDONLY|O_NONBLOCK,true);
   if(fd_dvr>=0) {
+    cDeCSA *decsa=cam ? cam->DeCSA() : 0;
     tsMutex.Lock();
     tsBuffer=new cDeCsaTSBuffer(fd_dvr,MEGABYTE(ScSetup.DeCsaTsBuffSize),CardIndex()+1,decsa,ScActive());
     tsMutex.Unlock();
@@ -1612,126 +457,3 @@ bool cScDevice::GetTSPacket(uchar *&Data)
 }
 
 #endif // !SASC
-
-bool cScDevice::SoftCSA(bool live)
-{
-  return softcsa && (!fullts || !live);
-}
-
-void cScDevice::CaidsChanged(void)
-{
-#ifndef SASC
-  if(ciadapter) ciadapter->CaidsChanged();
-  PRINTF(L_CORE_CAIDS,"caid list rebuild triggered");
-#endif // !SASC
-}
-
-bool cScDevice::SetCaDescr(ca_descr_t *ca_descr, bool initial)
-{
-#ifndef SASC
-  if(!softcsa || (fullts && ca_descr->index==0)) {
-    cMutexLock lock(&cafdMutex);
-    return ioctl(fd_ca,CA_SET_DESCR,ca_descr)>=0;
-    }
-  else if(decsa) return decsa->SetDescr(ca_descr,initial);
-#endif // !SASC
-  return false;
-}
-
-bool cScDevice::SetCaPid(ca_pid_t *ca_pid)
-{
-#ifndef SASC
-  if(!softcsa || (fullts && ca_pid->index==0)) {
-    cMutexLock lock(&cafdMutex);
-    return ioctl(fd_ca,CA_SET_PID,ca_pid)>=0;
-    }
-  else if(decsa) return decsa->SetCaPid(ca_pid);
-#endif // !SASC
-  return false;
-}
-
-int cScDevice::FilterHandle(void)
-{
-  return cScDevices::DvbOpen(DEV_DVB_DEMUX,DVB_DEV_SPEC,O_RDWR|O_NONBLOCK);
-}
-
-#ifndef SASC
-static unsigned int av7110_read(int fd, unsigned int addr)
-{
-  ca_pid_t arg;
-  arg.pid=addr;
-  ioctl(fd,CA_GET_MSG,&arg);
-  return arg.index;
-}
-#endif // !SASC
-
-#if 0
-static void av7110_write(int fd, unsigned int addr, unsigned int val)
-{
-  ca_pid_t arg;
-  arg.pid=addr;
-  arg.index=val;
-  ioctl(fd,CA_SEND_MSG,&arg);
-}
-#endif
-
-void cScDevice::DumpAV7110(void)
-{
-#ifndef SASC
-  if(LOG(L_CORE_AV7110)) {
-#define CODEBASE (0x2e000404+0x1ce00)
-    cMutexLock lock(&cafdMutex);
-    if(HasDecoder() && lastDump.Elapsed()>20000) {
-      lastDump.Set();
-      static unsigned int handles=0, hw_handles=0;
-      static const unsigned int code[] = {
-        0xb5100040,0x4a095a12,0x48094282,0xd00b4b09,0x20000044,
-        0x5b1c4294,0xd0033001,0x281cdbf8,0xe001f7fe,0xfd14bc10
-        };
-      static const unsigned int mask[] = {
-        0xffffffff,0xffffffff,0xffffffff,0xffffffff,0xffffffff,
-        0xffffffff,0xffffffff,0xffffffff,0xfffff800,0xf800ffff
-        };
-      if(!handles) {
-        handles=1;
-        PRINTF(L_CORE_AV7110,"searching handle tables");
-        for(int i=0; i<0x2000; i+=4) {
-          int j;
-          for(j=0; j<20; j+=4) {
-            int r=av7110_read(fd_ca,CODEBASE+i+j);
-            if((r&mask[j/4])!=(code[j/4]&mask[j/4])) break;
-            }
-          if(j==20) {
-            handles=av7110_read(fd_ca,CODEBASE+i+44);
-            hw_handles=av7110_read(fd_ca,CODEBASE+i+52);
-            PRINTF(L_CORE_AV7110,"found handles=%08x hw_handles=%08x at 0x%08x",handles,hw_handles,CODEBASE+i);
-            if((handles>>16)!=0x2e08 || (hw_handles>>16)!=0x2e08) {
-              PRINTF(L_CORE_AV7110,"seems to be invalid");
-              }
-            break;
-            }
-          }
-        }
-
-      unsigned int hdl=0, hwhdl=0;
-      PRINTF(L_CORE_AV7110,"         : 64000080 64000400");
-      for(int i=0; i<=31; i++) {
-        unsigned int off80 =av7110_read(fd_ca,0x64000080+i*4);
-        unsigned int off400=av7110_read(fd_ca,0x64000400+i*8);
-        LBSTART(L_CORE_AV7110);
-        LBPUT("handle %2d: %08x %08x %s pid=%04x idx=%d",
-          i,off80,off400,off80&0x2000?"ACT":"---",off80&0x1fff,(off400&0x1e)>>1);
-        if(handles>1 && i<=27) {
-          if((i&1)==0) {
-            hdl=av7110_read(fd_ca,handles+i*2);
-            hwhdl=av7110_read(fd_ca,hw_handles+i*2);
-            }
-          unsigned int s=((~i)&1)<<4;
-          LBPUT(" | %02d hdl=%04x hwfilt=%04x",i,(hdl>>s)&0xffff,(hwhdl>>s)&0xffff);
-          }
-        LBEND();
-        }
-      }
-    }
-#endif // !SASC
-}
index 5ad83f9712d310231026c4cc4975ab17a8cfbc59..737f1f9134cddc96b86b6ec6b42d8f321c51746d 100644 (file)
--- a/device.h
+++ b/device.h
 #ifndef ___DEVICE_H
 #define ___DEVICE_H
 
-#include <linux/dvb/ca.h>
 #include <vdr/dvbdevice.h>
 #include <vdr/thread.h>
-#include "misc.h"
-
-typedef int caid_t;
 
 class cCam;
 class cDeCSA;
@@ -34,60 +30,6 @@ class cScCiAdapter;
 
 // ----------------------------------------------------------------
 
-class cCaDescr {
-private:
-  unsigned char *descr;
-  int len;
-public:
-  cCaDescr(void);
-  cCaDescr(const cCaDescr &arg);
-  ~cCaDescr();
-  const unsigned char *Get(int &l) const;
-  void Set(const cCaDescr *d);
-  void Set(const unsigned char *de, int l);
-  void Clear(void);
-  bool operator== (const cCaDescr &arg) const;
-  void Join(const cCaDescr *cd, bool rev=false);
-  cString ToString(void);
-  };
-
-// ----------------------------------------------------------------
-
-class cPrgPid : public cSimpleItem {
-private:
-  bool proc;
-public:
-  int type, pid;
-  cCaDescr caDescr;
-  //
-  cPrgPid(int Type, int Pid) { type=Type; pid=Pid; proc=false; }
-  bool Proc(void) const { return proc; }
-  void Proc(bool is) { proc=is; };
-  };
-
-// ----------------------------------------------------------------
-
-class cPrg : public cSimpleItem {
-private:
-  bool isUpdate, pidCaDescr;
-  //
-  void Setup(void);
-public:
-  int sid, source, transponder;
-  cSimpleList<cPrgPid> pids;
-  cCaDescr caDescr;
-  //
-  cPrg(void);
-  cPrg(int Sid, bool IsUpdate);
-  bool IsUpdate(void) const { return isUpdate; }
-  bool HasPidCaDescr(void) const { return pidCaDescr; }
-  void SetPidCaDescr(bool val) { pidCaDescr=val; }
-  bool SimplifyCaDescr(void);
-  void DumpCaDescr(int c);
-  };
-
-// ----------------------------------------------------------------
-
 class cScDevices : public cDvbDevice {
 private:
   static int budget;
@@ -113,16 +55,13 @@ public:
 class cScDevice : public cDvbDevice {
 friend class cScDevices;
 private:
-  cDeCSA *decsa;
   cDeCsaTSBuffer *tsBuffer;
   cMutex tsMutex;
-  cScCiAdapter *ciadapter;
-  cCiAdapter *hwciadapter;
   cCam *cam;
+  cCiAdapter *hwciadapter;
   int fd_dvr, fd_ca, fd_ca2;
   bool softcsa, fullts;
-  cMutex cafdMutex;
-  cTimeMs lastDump;
+  char devId[8];
   //
 #ifndef SASC
   void LateInit(void);
@@ -145,13 +84,6 @@ public:
 #ifndef SASC
   virtual bool HasCi(void);
 #endif //SASC
-  virtual bool SetCaDescr(ca_descr_t *ca_descr, bool initial);
-  virtual bool SetCaPid(ca_pid_t *ca_pid);
-  int FilterHandle(void);
-  void DumpAV7110(void);
-  cCam *Cam(void) { return cam; }
-  bool SoftCSA(bool live);
-  void CaidsChanged(void);
   };
 
 #endif // ___DEVICE_H
index fd69536b42d9094cc2a1b17edf680955ed9cf6c6..c12477454d1062097c522cd252ad7f5c5883dbd6 100644 (file)
--- a/filter.c
+++ b/filter.c
 
 #include <linux/dvb/dmx.h>
 
+#include <vdr/device.h>
 #include <vdr/tools.h>
 
 #include "filter.h"
-#include "sc.h"
 #include "misc.h"
 #include "log-core.h"
 
 // -- cPidFilter ------------------------------------------------------------------
 
-cPidFilter::cPidFilter(const char *Id, int Num, int DvbNum, unsigned int IdleTime)
+cPidFilter::cPidFilter(const char *Id, int Num, cDevice *Device, unsigned int IdleTime)
 {
-  dvbNum=DvbNum;
+  device=Device;
   idleTime=IdleTime;
-  id=0; fd=-1; active=false; forceRun=false; userData=0;
+  id=0; fd=-1; forceRun=false; userData=0;
   id=bprintf("%s/%d",Id,Num);
-  PRINTF(L_CORE_ACTION,"new filter '%s' on card %d (%d ms)",id,dvbNum,idleTime);
+  PRINTF(L_CORE_ACTION,"new filter '%s' (%d ms)",id,idleTime);
 }
 
 cPidFilter::~cPidFilter()
 {
   cMutexLock lock(this);
-  if(fd>=0) {
-    Stop();
-    close(fd);
-    }
-  PRINTF(L_CORE_ACTION,"filter '%s' on card %d removed",id,dvbNum);
+  Stop();
+  PRINTF(L_CORE_ACTION,"filter '%s' removed",id);
   free(id);
 }
 
-bool cPidFilter::Open(void)
-{
-  cMutexLock lock(this);
-  if(fd<0) {
-    fd=cSoftCAM::FilterHandle(dvbNum);
-    if(fd>=0) return true;
-    }
-  return false;
-}
-
 void cPidFilter::Flush(void)
 {
   cMutexLock lock(this);
@@ -75,28 +62,17 @@ void cPidFilter::Flush(void)
     }
 }
 
-void cPidFilter::Start(int Pid, int Section, int Mask, int Mode, bool Crc)
+void cPidFilter::Start(int Pid, int Section, int Mask)
 {
   cMutexLock lock(this);
+  Stop();
+  fd=device->OpenFilter(Pid,Section,Mask);
   if(fd>=0) {
-    Stop();
-    struct dmx_sct_filter_params FilterParams;
-    memset(&FilterParams,0,sizeof(FilterParams));
-    FilterParams.filter.filter[0]=Section;
-    FilterParams.filter.mask[0]=Mask;
-    FilterParams.filter.mode[0]=Mode;
-    FilterParams.flags=DMX_IMMEDIATE_START;
-    if(Crc) FilterParams.flags|=DMX_CHECK_CRC;
-    FilterParams.pid=Pid;
-    if(ioctl(fd,DMX_SET_FILTER,&FilterParams)<0) {
-      PRINTF(L_GEN_ERROR,"filter '%s': DMX_SET_FILTER failed: %s",id,strerror(errno));
-      return;
-      }
     pid=Pid;
-    active=true;
 
     LBSTART(L_CORE_ACTION);
-    LBPUT("filter '%s' -> pid=0x%04x sct=0x%02x/0x%02x/0x%02x crc=%d matching",id,Pid,Section,Mask,Mode,Crc);
+    LBPUT("filter '%s' -> pid=0x%04x sct=0x%02x/0x%02x matching",id,Pid,Section,Mask);
+    int Mode=0;
     int mam =Mask &  (~Mode);
     int manm=Mask & ~(~Mode);
     for(int i=0; i<256; i++) {
@@ -112,10 +88,7 @@ void cPidFilter::Start(int Pid, int Section, int Mask, int Mode, bool Crc)
 void cPidFilter::Stop(void)
 {
   cMutexLock lock(this);
-  if(fd>=0) {
-    CHECK(ioctl(fd,DMX_STOP));
-    active=false;
-    }
+  if(fd>=0) { device->CloseFilter(fd); fd=-1; }
 }
 
 void cPidFilter::SetBuffSize(int BuffSize)
@@ -144,15 +117,15 @@ void cPidFilter::Wakeup(void)
 
 int cPidFilter::Pid(void)
 {
-  return active ? pid : -1;
+  return Active() ? pid : -1;
 }
 
 // -- cAction ------------------------------------------------------------------
 
-cAction::cAction(const char *Id, int DvbNum)
+cAction::cAction(const char *Id, cDevice *Device, const char *DevId)
 {
-  id=bprintf("%s %d",Id,DvbNum);
-  dvbNum=DvbNum;
+  device=Device; devId=DevId;
+  id=bprintf("%s %s",Id,DevId);
   unique=0; pri=-1;
   SetDescription("%s filter",id);
 }
@@ -165,27 +138,24 @@ cAction::~cAction()
   free(id);
 }
 
-cPidFilter *cAction::CreateFilter(const char *Id, int Num, int DvbNum, int IdleTime)
+cPidFilter *cAction::CreateFilter(int Num, int IdleTime)
 {
-  return new cPidFilter(Id,Num,DvbNum,IdleTime);
+  return new cPidFilter(id,Num,device,IdleTime);
 }
 
 cPidFilter *cAction::NewFilter(int IdleTime)
 {
   Lock();
-  cPidFilter *filter=CreateFilter(id,unique++,dvbNum,IdleTime);
-  if(filter && filter->Open()) {
+  cPidFilter *filter=CreateFilter(unique++,IdleTime);
+  if(filter) {
     if(!Active()) {
       Start();
       PRINTF(L_CORE_ACTION,"%s: started",id);
       }
     filters.Add(filter);
     }
-  else {
-    PRINTF(L_CORE_ACTION,"%s: filter '%s' failed to open",id,filter?filter->id:"XxX");
-    delete filter;
-    filter=0;
-    }
+  else
+    PRINTF(L_CORE_ACTION,"%s: failed to create filter",id);
   Unlock();
   return filter;
 }
@@ -238,12 +208,13 @@ void cAction::Action(void)
         }
       int num=0;
       cPidFilter *filter;
-      for(filter=filters.First(); filter; filter=filters.Next(filter)) {
-        memset(&pfd[num],0,sizeof(struct pollfd));
-        pfd[num].fd=filter->fd;
-        pfd[num].events=POLLIN;
-        num++;
-        }
+      for(filter=filters.First(); filter; filter=filters.Next(filter))
+        if(filter->Active()) {
+          memset(&pfd[num],0,sizeof(struct pollfd));
+          pfd[num].fd=filter->fd;
+          pfd[num].events=POLLIN;
+          num++;
+          }
       Unlock();
 
       // now poll for data
@@ -261,7 +232,10 @@ void cAction::Action(void)
                 unsigned char buff[MAX_SECT_SIZE];
                 int n=read(filter->fd,buff,sizeof(buff));
                 if(n<0 && errno!=EAGAIN) {
-                  if(errno==EOVERFLOW) PRINTF(L_GEN_ERROR,"action %s read: Buffer overflow",filter->id);
+                  if(errno==EOVERFLOW) {
+                    filter->Flush();
+                    //PRINTF(L_GEN_ERROR,"action %s read: Buffer overflow",filter->id);
+                    }
                   else PRINTF(L_GEN_ERROR,"action %s read: %s",filter->id,strerror(errno));
                   }
                 if(n>0) {
index f93c67123d6fa61eef08400b9b3cea92a140fc06..329a29c4a1b95b034b98d8a44704b540fb9cf62c 100644 (file)
--- a/filter.h
+++ b/filter.h
@@ -23,6 +23,7 @@
 #include <vdr/thread.h>
 #include "misc.h"
 
+class cDevice;
 class cPidFilter;
 
 // ----------------------------------------------------------------
@@ -31,13 +32,16 @@ class cPidFilter;
 
 class cAction : protected cThread {
 private:
-  char *id;
-  int dvbNum, unique, pri;
+  const char *devId;
+  int unique, pri;
   cSimpleList<cPidFilter> filters;
 protected:
+  cDevice *device;
+  char *id;
+  //
   virtual void Process(cPidFilter *filter, unsigned char *data, int len)=0;
   virtual void Action(void);
-  virtual cPidFilter *CreateFilter(const char *Id, int Num, int DvbNum, int IdleTime);
+  virtual cPidFilter *CreateFilter(int Num, int IdleTime);
   //
   cPidFilter *NewFilter(int IdleTime);
   cPidFilter *IdleFilter(void);
@@ -45,7 +49,7 @@ protected:
   void DelAllFilter(void);
   void Priority(int Pri);
 public:
-  cAction(const char *Id, int DvbNum);
+  cAction(const char *Id, cDevice *Device, const char *DevId);
   virtual ~cAction();
   };
 
@@ -54,30 +58,27 @@ public:
 class cPidFilter : public cSimpleItem, private cMutex {
 friend class cAction;
 private:
-  int dvbNum;
+  cDevice *device;
   unsigned int idleTime;
   cTimeMs lastTime;
   bool forceRun;
-  //
-  bool Open(void);
 protected:
   char *id;
   int fd;
   int pid;
-  bool active;
 public:
   void *userData;
   //
-  cPidFilter(const char *Id, int Num, int DvbNum, unsigned int IdleTime);
+  cPidFilter(const char *Id, int Num, cDevice *Device, unsigned int IdleTime);
   virtual ~cPidFilter();
   void Flush(void);
-  virtual void Start(int Pid, int Section, int Mask, int Mode, bool Crc);
+  virtual void Start(int Pid, int Section, int Mask);
   void Stop(void);
-  void Wakeup(void);
   void SetBuffSize(int BuffSize);
+  void Wakeup(void);
   int SetIdleTime(unsigned int IdleTime);
   int Pid(void);
-  bool Active(void) { return active; }
+  bool Active(void) { return fd>=0; }
   };
 
 #endif //___FILTER_H
diff --git a/global.h b/global.h
new file mode 100644 (file)
index 0000000..a2defce
--- /dev/null
+++ b/global.h
@@ -0,0 +1,33 @@
+/*
+ * Softcam plugin to VDR (C++)
+ *
+ * This code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef ___GLOBAL_H
+#define ___GLOBAL_H
+
+// ----------------------------------------------------------------
+
+class cGlobal {
+public:
+  static bool Active(bool log);
+  static void HouseKeeping(void);
+  static char *CurrKeyStr(int cardindex, int num, const char **id);
+  static void CaidsChanged(void);
+  };
+
+#endif // ___GLOBAL_H
index d4e87436e1fa2270581c45f5a56824afaf7f3c02..26193853ce9a707899206a286c423554016df133 100644 (file)
@@ -24,7 +24,7 @@
 #include <vdr/sources.h>
 
 #include "override.h"
-#include "sc.h"
+#include "global.h"
 #include "misc.h"
 #include "log-core.h"
 
@@ -563,7 +563,7 @@ void cOverrides::PreLoad(void)
 
 void cOverrides::PostLoad(void)
 {
-  if(caidTrigger) cSoftCAM::CaidsChanged();
+  if(caidTrigger) cGlobal::CaidsChanged();
 }
 
 cOverride *cOverrides::ParseLine(char *line)
index 48bf38cf8401ba2b1465520b9cfb40eb1aae4ba0..994964ac0fec9a915dfd40e31e7238b306cffd7c 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2007-08-27 12:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-15\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(keiner)"
+
 msgid "Key update"
 msgstr "Key Update"
 
@@ -106,9 +109,6 @@ msgstr "Dateien wirklich neu laden?"
 msgid "Active! Can't reload files now"
 msgstr "Aktiv! Kann Dateien jetzt nicht neu laden"
 
-msgid "(none)"
-msgstr "(keiner)"
-
 msgid "active CAIDs"
 msgstr "aktive CAIDs"
 
index 16f4ad559ce55a586d0c2c025afe9116680ebfef..e740907f64035c7eb3c39dfb55a5e78b70ea6a32 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2008-11-19 13:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-15\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(ei)"
+
 msgid "Key update"
 msgstr "Avaimen päivitys"
 
@@ -106,9 +109,6 @@ msgstr "Ladataanko avaintiedostot uudelleen?"
 msgid "Active! Can't reload files now"
 msgstr "Aktiivinen! Uudelleen lataus ei onnistu"
 
-msgid "(none)"
-msgstr "(ei)"
-
 msgid "active CAIDs"
 msgstr "aktiiviset CAID:t"
 
index 34ba34470d00485008362c021b602ff3fb470a4c..c2a10e1d7111dfac9e732df3c5847486be821af7 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2007-08-27 12:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-1\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(aucune)"
+
 msgid "Key update"
 msgstr "Mise à jour des clés"
 
@@ -106,9 +109,6 @@ msgstr "Recharger les fichiers?"
 msgid "Active! Can't reload files now"
 msgstr "Actif! Impossible de recharger les fichiers"
 
-msgid "(none)"
-msgstr "(aucune)"
-
 msgid "active CAIDs"
 msgstr "CAIDs actifs"
 
index 269aed9ea5db29242cb0ba686195d833747c1f69..d7ff80b54b900d5079b9059db6ab0e87ef4810f0 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.11\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2009-05-17 11:09+0800\n"
 "Last-Translator: jv\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-2\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(nincs)"
+
 msgid "Key update"
 msgstr ""
 
@@ -106,9 +109,6 @@ msgstr "Biztos, hogy 
 msgid "Active! Can't reload files now"
 msgstr "SC aktív! Nem tud újraolvasni."
 
-msgid "(none)"
-msgstr "(nincs)"
-
 msgid "active CAIDs"
 msgstr "aktív CAIDok"
 
index 5e8e1ce7d149a384aa47393b4120c89d6241a82e..2f5d3c44ec326741cce280520adc2a57396d03f7 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2008-11-19 12:23+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-15\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(nessuna)"
+
 msgid "Key update"
 msgstr "Aggiornamento chiavi"
 
@@ -106,9 +109,6 @@ msgstr "Ricaricare il file delle chiavi?"
 msgid "Active! Can't reload files now"
 msgstr "Chiave in uso! Impossibile ricaricare adesso"
 
-msgid "(none)"
-msgstr "(nessuna)"
-
 msgid "active CAIDs"
 msgstr "CAIDs attivi"
 
index ff0fcb90047d2bd8484f9017d95492b1c946eec2..57232563a7382f5cbc418440e380f0f7541573f9 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.7.10\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2007-08-27 12:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(nėra)"
+
 msgid "Key update"
 msgstr "Raktų atnaujinimas"
 
@@ -106,9 +109,6 @@ msgstr "Tikrai perkrauti failus?"
 msgid "Active! Can't reload files now"
 msgstr "Servisas aktyvus! Dabar negali perkrauti failų"
 
-msgid "(none)"
-msgstr "(nėra)"
-
 msgid "active CAIDs"
 msgstr "aktyvūs CAIDai"
 
index 023df14fd2dba0e1b84fd2b6b552d439e44fb2f6..76709a028c7982793d82194018f7142d5a715c09 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2007-08-27 12:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-15\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(geen)"
+
 msgid "Key update"
 msgstr ""
 
@@ -106,9 +109,6 @@ msgstr "Werkelijk opnieuw laden bestanden?"
 msgid "Active! Can't reload files now"
 msgstr "Actief! Kan bestanden niet herladen"
 
-msgid "(none)"
-msgstr "(geen)"
-
 msgid "active CAIDs"
 msgstr "actieve CAIDS"
 
index 38efa532e1aa412674365fef4784419934399eeb..3a5804985696d91f66a2102a34619d2fbbe91bb7 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2007-08-27 12:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-2\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(brak)"
+
 msgid "Key update"
 msgstr ""
 
@@ -106,9 +109,6 @@ msgstr "Na pewno prze
 msgid "Active! Can't reload files now"
 msgstr "Aktywny! Nie mo¿na teraz prze³adowaæ plików."
 
-msgid "(none)"
-msgstr "(brak)"
-
 msgid "active CAIDs"
 msgstr "aktywne CAID"
 
index 25e7d1b6e92955dd3461215ae7fe4ca0e6b93c93..cbd4108c369ef9d15dda76d9c30a55c807d66162 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2009-05-14 19:33+0100\n"
 "Last-Translator: somebody\n"
 "Language-Team: ru\n"
@@ -15,6 +15,9 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "X-Generator: KBabel 1.11.4\n"
 
+msgid "(none)"
+msgstr "(ÝÕâ)"
+
 msgid "Key update"
 msgstr "¾ÑÝÞÒÛÕÝØÕ ÚÛîçÐ"
 
@@ -107,9 +110,6 @@ msgstr "
 msgid "Active! Can't reload files now"
 msgstr "·ÐÝïâ! ½Õ ÜÞÓã ßÕàÕ×ÐÓàãרâì äÐÙÛë"
 
-msgid "(none)"
-msgstr "(ÝÕâ)"
-
 msgid "active CAIDs"
 msgstr "ÐÚâØÒÝëÕ CAID"
 
index a683ff102b5f5d7453b0f11cf988880d53177d29..1ab7c0c02e3bbe31e922c43e1f1aaaf2b23185d1 100644 (file)
@@ -6,7 +6,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: VDR 1.5.9\n"
 "Report-Msgid-Bugs-To: <noone@nowhere.org>\n"
-"POT-Creation-Date: 2010-12-12 13:24+0100\n"
+"POT-Creation-Date: 2011-08-06 20:19+0200\n"
 "PO-Revision-Date: 2007-08-27 12:45+0200\n"
 "Last-Translator: somebody\n"
 "Language-Team: somebody\n"
@@ -14,6 +14,9 @@ msgstr ""
 "Content-Type: text/plain; charset=ISO-8859-1\n"
 "Content-Transfer-Encoding: 8bit\n"
 
+msgid "(none)"
+msgstr "(ingen)"
+
 msgid "Key update"
 msgstr ""
 
@@ -106,9 +109,6 @@ msgstr "Bekr
 msgid "Active! Can't reload files now"
 msgstr "Aktiv! Kan inte ladda om filer nu"
 
-msgid "(none)"
-msgstr "(ingen)"
-
 msgid "active CAIDs"
 msgstr "aktiva CAID"
 
diff --git a/sc.c b/sc.c
index d0678a2b5a283ac36bc14eacbd407689ba7c9c65..f19928dd89ba11a0625d026e8bde7ecc3e22473b 100644 (file)
--- a/sc.c
+++ b/sc.c
 #include <vdr/tools.h>
 #include <vdr/config.h>
 
-#include "sc.h"
 #include "scsetup.h"
 #include "filter.h"
 #include "system.h"
 #include "cam.h"
+#include "global.h"
 #include "device.h"
 #include "smartcard.h"
 #include "data.h"
@@ -525,6 +525,34 @@ void cOpts::Create(cOsdMenu *menu)
     }
 }
 
+// --- cSoftCAM ---------------------------------------------------------------
+
+class cSoftCAM {
+public:
+  static bool Load(const char *cfgdir);
+  static void Shutdown(void);
+  };
+
+bool cSoftCAM::Load(const char *cfgdir)
+{
+  if(!Feature.KeyFile()) keys.Disable();
+  if(!Feature.SmartCard()) smartcards.Disable();
+  cStructLoaders::Load(false);
+  if(Feature.KeyFile() && keys.Count()<1)
+    PRINTF(L_GEN_ERROR,"no keys loaded for softcam!");
+  if(!cSystems::Init(cfgdir)) return false;
+  srand(time(0));
+  return true;
+}
+
+void cSoftCAM::Shutdown(void)
+{
+  cStructLoaders::Save(true);
+  cSystems::Clean();
+  smartcards.Shutdown();
+  keys.SafeClear();
+}
+
 // --- cMenuInfoSc -------------------------------------------------------------
 
 class cMenuInfoSc : public cOsdMenu {
@@ -537,19 +565,22 @@ cMenuInfoSc::cMenuInfoSc(void)
 :cOsdMenu(tr("SoftCAM"),25)
 {
   Add(new cScInfoItem(tr("Current keys:")));
-  for(int d=0; d<MAXDVBDEVICES; d++) {
-    int n=0;
+  int d=0, n;
+  do {
+    n=0;
     char *ks;
     do {
-      if((ks=cSoftCAM::CurrKeyStr(d,n))) {
+      const char *id;
+      if((ks=cGlobal::CurrKeyStr(d,n,&id))) {
         char buffer[32];
-        snprintf(buffer,sizeof(buffer),"  [%s %d:%d]","DVB",d+1,n+1);
+        snprintf(buffer,sizeof(buffer),"  [%s.%d]",id,n);
         Add(new cScInfoItem(buffer,ks));
         free(ks);
+        n++;
         }
-      n++;
       } while(ks);
-    }
+    d++;
+    } while(n>0);
   if(Feature.KeyFile()) {
     Add(new cScInfoItem(tr("Key update status:")));
     int fk, nk;
@@ -901,7 +932,7 @@ eOSState cMenuSetupSc::ProcessKey(eKeys Key)
 
     case osUser9:
       state=osContinue;
-      if(!cSoftCAM::Active(true)) {
+      if(!cGlobal::Active(true)) {
         if(Interface->Confirm(tr("Really reload files?"))) {
           Store();
           cSoftCAM::Load(cfgdir);
@@ -987,80 +1018,6 @@ bool cScSetup::CapCheck(int n)
   return false;
 }
 
-// --- cSoftCAM ---------------------------------------------------------------
-
-bool cSoftCAM::Load(const char *cfgdir)
-{
-  if(!Feature.KeyFile()) keys.Disable();
-  if(!Feature.SmartCard()) smartcards.Disable();
-  cStructLoaders::Load(false);
-  if(Feature.KeyFile() && keys.Count()<1)
-    PRINTF(L_GEN_ERROR,"no keys loaded for softcam!");
-  if(!cSystems::Init(cfgdir)) return false;
-  srand(time(0));
-  return true;
-}
-
-void cSoftCAM::Shutdown(void)
-{
-  cStructLoaders::Save(true);
-  cSystems::Clean();
-  smartcards.Shutdown();
-  keys.SafeClear();
-}
-
-char *cSoftCAM::CurrKeyStr(int CardNum, int num)
-{
-  cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
-  char *str=0;
-  if(dev) {
-    if(dev->Cam()) str=dev->Cam()->CurrentKeyStr(num);
-    if(!str && num==0 && ScSetup.CapCheck(CardNum)) str=strdup(tr("(none)"));
-    }
-  return str;
-}
-
-bool cSoftCAM::Active(bool log)
-{
-  for(int n=cDevice::NumDevices(); --n>=0;) {
-    cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
-    if(dev && dev->Cam() && dev->Cam()->Active(log)) return true;
-    }
-  return false;
-}
-
-void cSoftCAM::SetLogStatus(int CardNum, const cEcmInfo *ecm, bool on)
-{
-  cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
-  if(dev && dev->Cam()) dev->Cam()->LogEcmStatus(ecm,on);
-}
-
-void cSoftCAM::AddHook(int CardNum, cLogHook *hook)
-{
-  cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
-  if(dev && dev->Cam()) dev->Cam()->AddHook(hook);
-}
-
-bool cSoftCAM::TriggerHook(int CardNum, int id)
-{
-  cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
-  return dev && dev->Cam() && dev->Cam()->TriggerHook(id);
-}
-
-void cSoftCAM::CaidsChanged(void)
-{
-  for(int n=cDevice::NumDevices(); --n>=0;) {
-    cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
-    if(dev) dev->CaidsChanged();
-    }
-}
-
-int cSoftCAM::FilterHandle(int CardNum)
-{
-  cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
-  return dev ? dev->FilterHandle() : -1;
-}
-
 // --- cScHousekeeper ----------------------------------------------------------
 
 class cScHousekeeper : public cThread {
@@ -1088,17 +1045,12 @@ void cScHousekeeper::Action(void)
   while(Running()) {
     if(++c==20) {
       c=0;
-      for(int n=cDevice::NumDevices(); --n>=0;) {
-        cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
-        if(dev && dev->Cam()) dev->Cam()->HouseKeeping();
-        }
+      cGlobal::HouseKeeping();
       }
-
     if(Feature.KeyFile()) keys.HouseKeeping();
-    if(!cSoftCAM::Active(false)) cStructLoaders::Purge();
+    if(!cGlobal::Active(false)) cStructLoaders::Purge();
     cStructLoaders::Load(true);
     cStructLoaders::Save();
-
     cCondWait::SleepMs(987);
     }
 }
@@ -1415,7 +1367,7 @@ const char **cScPlugin::SVDRPHelpPages(void)
 cString cScPlugin::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode)
 {
   if(!strcasecmp(Command,"RELOAD")) {
-    if(cSoftCAM::Active(true)) {
+    if(cGlobal::Active(true)) {
       ReplyCode=550;
       return "Softcam active. Can't reload files now";
       }
diff --git a/sc.h b/sc.h
deleted file mode 100644 (file)
index 5e0717e..0000000
--- a/sc.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Softcam plugin to VDR (C++)
- *
- * This code is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
- */
-
-#ifndef ___SC_H
-#define ___SC_H
-
-class cEcmInfo;
-class cLogHook;
-
-// ----------------------------------------------------------------
-
-class cSoftCAM {
-public:
-  static bool Load(const char *cfgdir);
-  static void Shutdown(void);
-  //
-  static bool Active(bool log);
-  static char *CurrKeyStr(int CardNum, int num);
-  static void SetLogStatus(int CardNum, const cEcmInfo *ecm, bool on);
-  static void AddHook(int CardNum, cLogHook *hook);
-  static bool TriggerHook(int CardNum, int id);
-  static void CaidsChanged(void);
-  static int FilterHandle(int CardNum);
-  };
-
-#endif // ___SC_H
index 55e6d42f701f0281744f0445ad311af8a3f417b5..ea5008852f3598b1442b31ae71edca0a4a8dcc47 100644 (file)
@@ -32,7 +32,7 @@
 #include <vdr/thread.h>
 
 #include "smartcard.h"
-#include "sc.h"
+#include "global.h"
 #include "misc.h"
 #include "log-core.h"
 
@@ -2001,7 +2001,7 @@ int cSmartCard::CheckSctLen(const unsigned char *data, int off)
 
 void cSmartCard::CaidsChanged(void)
 {
-  cSoftCAM::CaidsChanged();
+  cGlobal::CaidsChanged();
 }
 
 // -- cSmartCardLink -----------------------------------------------------------
index f8c3a1b8fcb44fc155d949f48c27021c7090a275..3e96c9a7dd42fe20f6550af56868f2471beeb42b 100644 (file)
--- a/system.c
+++ b/system.c
@@ -25,8 +25,9 @@
 
 #include <openssl/md5.h>
 
-#include "sc.h"
 #include "system.h"
+#include "cam.h"
+#include "global.h"
 #include "data.h"
 #include "override.h"
 #include "opts.h"
@@ -98,7 +99,7 @@ int cSystem::newKeys=0;
 cSystem::cSystem(const char *Name, int Pri)
 {
   name=Name; pri=Pri;
-  currentKeyStr[0]=0; doLog=true; cardNum=-1; logecm=0;
+  currentKeyStr[0]=0; doLog=true; cam=0; logecm=0;
   check=new struct EcmCheck;
   memset(check,0,sizeof(struct EcmCheck));
   memset(cw,0,sizeof(cw));
@@ -114,21 +115,36 @@ cSystem::cSystem(const char *Name, int Pri)
 cSystem::~cSystem()
 {
   delete check;
-  if(logecm) cSoftCAM::SetLogStatus(cardNum,logecm,false);
+  if(logecm && cam) cam->LogEcmStatus(logecm,false);
   delete logecm;
 }
 
 void cSystem::StartLog(const cEcmInfo *ecm, int caid)
 {
   if(!logecm || logecm->caId!=caid) {
-    if(logecm) cSoftCAM::SetLogStatus(cardNum,logecm,false);
+    if(logecm && cam) cam->LogEcmStatus(logecm,false);
     delete logecm;
     logecm=new cEcmInfo(ecm);
     logecm->caId=caid; logecm->emmCaId=0;
-    cSoftCAM::SetLogStatus(cardNum,logecm,true);
+    if(cam) cam->LogEcmStatus(logecm,true);
     }
 }
 
+void cSystem::AddHook(cLogHook *hook)
+{
+  if(cam) cam->AddHook(hook);
+}
+
+bool cSystem::TriggerHook(int id)
+{
+  return cam && cam->TriggerHook(id);
+}
+
+void cSystem::CaidsChanged(void)
+{
+  cGlobal::CaidsChanged();
+}
+
 void cSystem::ParseCADescriptor(cSimpleList<cEcmInfo> *ecms, unsigned short sysId, int source, const unsigned char *data, int len)
 {
   const int pid=WORD(data,2,0x1FFF);
@@ -166,10 +182,11 @@ void cSystem::ParseCAT(cPids *pids, const unsigned char *buffer, int source, int
           }
         break;
       case 0x05: // Viaccess style (88/8c/8d/8e)
-        pids->AddPid(pid,0x8B,0xFE,0x07); // mismatching 89/8f
+        pids->AddPid(pid,0x88,0xF9); // mismatching 8a
+        pids->AddPid(pid,0x8D,0xFF);
         break;
       case 0x0d: // Cryptoworks style (82/84/86/88/89)
-        pids->AddPid(pid,0x80,0xFF,0x06);
+        pids->AddPid(pid,0x82,0xF9); // mismatching 80
         pids->AddPid(pid,0x88,0xFE);
         break;
       case 0x18: // Nagra style (82/83)
index 524ad57f160045777152997d090e33d28e9ff188..f22e4a98756a8e342cfdc375aaed1f73a7a2b55f 100644 (file)
--- a/system.h
+++ b/system.h
@@ -38,6 +38,7 @@ class cSystems;
 class cLogger;
 class cOpts;
 class cHookManager;
+class cCam;
 
 // ----------------------------------------------------------------
 
@@ -71,7 +72,8 @@ public:
 class cLogHook : public cSimpleItem {
 friend class cHookManager;
 private:
-  int cardNum, id;
+//  int cardNum, id;
+  int id;
   const char *name;
   cTimeMs delay;
   bool bailOut;
@@ -92,12 +94,13 @@ class cSystem : public cSimpleItem {
 friend class cKeySnoop;
 private:
   static int foundKeys, newKeys;
-  int pri, cardNum;
+  int pri;
   cLastKey lastkey;
   char *lastTxt;
   char currentKeyStr[48];
   struct EcmCheck *check;
   cEcmInfo *logecm;
+  cCam *cam;
 protected:
   const char *name;
   unsigned char cw[16];
@@ -113,25 +116,31 @@ protected:
 public:
   cSystem(const char *Name, int Pri);
   virtual ~cSystem();
+  void SetOwner(cCam *Cam) { cam=Cam; }
+  static void CaidsChanged(void);
+  //
   virtual int CheckECM(const cEcmInfo *ecm, const unsigned char *data, bool sync);
   virtual void CheckECMResult(const cEcmInfo *ecm, const unsigned char *data, bool result);
   virtual bool ProcessECM(const cEcmInfo *ecm, unsigned char *buffer)=0;
   virtual void ProcessEMM(int pid, int caid, const unsigned char *buffer) {};
   virtual void ParseCADescriptor(cSimpleList<cEcmInfo> *ecms, unsigned short sysId, int source, const unsigned char *data, int len);
   virtual void ParseCAT(cPids *pids, const unsigned char *buffer, int source, int transponder);
+  //
+  void AddHook(cLogHook *hook);
+  bool TriggerHook(int id);
+  //
   unsigned char *CW(void) { return cw; }
   void DoLog(bool Log) { doLog=Log; }
   int Pri(void) { return pri; }
   const char *CurrentKeyStr(void) { return currentKeyStr; }
   const char *Name(void) { return name; }
-  int CardNum(void) { return cardNum; }
-  void CardNum(int CardNum) { cardNum=CardNum; }
   int MaxEcmTry(void) { return maxEcmTry; }
   bool HasLogger(void) { return hasLogger; }
   bool NeedsLogger(void) { return needsLogger; }
   bool Local(void) { return local; }
   bool NeedsData(void) { return needsDescrData; }
   bool Constant(void) { return constant; }
+  //
   static void FoundKey(void) { foundKeys++; }
   static void NewKey(void) { newKeys++; }
   static void KeyStats(int &fk, int &nk) { fk=foundKeys; nk=newKeys; }
index 608f9c82212a611a03933326b17d8e854026345d..75b16f4e2573dc0a8dadfe8b60c416902da5a5ec 100644 (file)
@@ -32,7 +32,7 @@ public:
   cCardClientAroureos(const char *Name);
   virtual bool Init(const char *config);
   virtual bool Login(void);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
   virtual bool ProcessEMM(int caSys, const unsigned char *source);
   };
 
@@ -99,7 +99,7 @@ bool cCardClientAroureos::ProcessEMM(int caSys, const unsigned char *source)
   return false;
 }
 
-bool cCardClientAroureos::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum)
+bool cCardClientAroureos::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
 {
   cMutexLock lock(this);
   so.Flush();
index e779aab018a6e3f191bb3dbad0391f634104afb1..9c86a8d781a38d83b589e698048b39e5f51fde26 100644 (file)
@@ -56,7 +56,7 @@ public:
   virtual bool Init(const char *config);
   virtual bool Login(void);
   virtual bool Immediate(void);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
   virtual bool ProcessEMM(int caSys, const unsigned char *source);
   };
 
@@ -200,7 +200,7 @@ bool cCardClientCommon::ProcessEMM(int caSys, const unsigned char *source)
   return false;
 }
 
-bool cCardClientCommon::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum)
+bool cCardClientCommon::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
 {
   Lock();
   bool res=false;
@@ -442,7 +442,7 @@ public:
   cCardClientCamd35(const char *Name);
   virtual bool Init(const char *config);
   virtual bool Login(void);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw);
   virtual bool ProcessEMM(int caSys, const unsigned char *data);
   };
 
@@ -673,7 +673,7 @@ bool cCardClientCamd35::ProcessEMM(int caSys, const unsigned char *data)
   return false;
 }
 
-bool cCardClientCamd35::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+bool cCardClientCamd35::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
 {
   bool res=false;
   const int length=SCT_LEN(data);
index 26430c077368d63c6a6d3bc20484267322ee8671..2fb4f46eb804dcb482af91b519cd481edc7f0f63 100644 (file)
@@ -25,7 +25,6 @@
 
 #include "system.h"
 #include "cc.h"
-#include "sc.h"
 #include "misc.h"
 #include "opts.h"
 #include "log-core.h"
@@ -67,7 +66,7 @@ bool cCardClient::Immediate(void)
 
 void cCardClient::CaidsChanged(void)
 {
-  cSoftCAM::CaidsChanged();
+  cSystem::CaidsChanged();
 }
 
 bool cCardClient::ParseStdConfig(const char *config, int *num)
@@ -212,7 +211,7 @@ bool cSystemCardClient::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
     if(cc) {
       cTimeMs start;
       int id=cc->msECM.Get(data,SCT_LEN(data),cw);
-      if(id==0 || (id>0 && cc->ProcessECM(ecm,data,cw,CardNum()))) {
+      if(id==0 || (id>0 && cc->ProcessECM(ecm,data,cw))) {
         int dur=start.Elapsed();
         if(dur>2000) {
           char bb[32];
index 645c46daedd9648510f1b3bdb17a7879d7fc5b42..de968e03092b2c17974b8db39141c7172222bee6 100644 (file)
@@ -78,7 +78,7 @@ public:
   virtual bool Login(void)=0;
   virtual bool Immediate(void);
   virtual bool CanHandle(unsigned short SysId);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)=0;
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)=0;
   virtual bool ProcessEMM(int caSys, const unsigned char *data) { return false; }
   const char *Name(void) { return name; }
   };
index 9f5cb525ca42ebf844dda9a286d69118eb8098e1..f3523722249dbccdd9d84327926caf4ebaef4120 100644 (file)
@@ -174,7 +174,7 @@ public:
   ~cCardClientCCcam();\r
   virtual bool Init(const char *CfgDir);\r
   virtual bool Login(void);\r
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);\r
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);\r
   };\r
 \r
 static cCardClientLinkReg<cCardClientCCcam> __ncd("cccam");\r
@@ -218,11 +218,17 @@ bool cCardClientCCcam::Login(void)
   return true;\r
 }\r
 \r
-bool cCardClientCCcam::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)\r
+bool cCardClientCCcam::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)\r
 {\r
   cMutexLock lock(this);\r
   if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;\r
 \r
+  if(ecm->dvbAdapter<0 || ecm->dvbFrontend!=0) {\r
+    PRINTF(L_CC_CCCAM,"cannot handle DVB adapter %d, frontend %d",ecm->dvbAdapter,ecm->dvbFrontend);\r
+    return false;\r
+    }\r
+  int cardnum=ecm->dvbAdapter;\r
+\r
   cCCcamCard *c=&card[cardnum];\r
   int timeout=3000;\r
   if(ecm->ecm_pid!=c->Pid() || !c->Connected()) { // channel change\r
index 1d4e4e65746c1e49883f415917b396500ac8127a..c6d5401982923708add1bf7d335e4afd8b67aae1 100644 (file)
@@ -680,7 +680,7 @@ public:
   virtual bool Init(const char *CfgDir);
   virtual bool Login(void);
   virtual bool CanHandle(unsigned short SysId);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
   virtual bool ProcessEMM(int caSys, const unsigned char *data);
   };
 
@@ -1147,12 +1147,12 @@ bool cCardClientCCcam2::Login(void)
   return true;
 }
 
-bool cCardClientCCcam2::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum)
+bool cCardClientCCcam2::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw)
 {
   cMutexLock lock(this);
   if(!so.Connected() && !Login()) { Logout(); return false; }
   if(!CanHandle(ecm->caId)) return false;
-  PRINTF(L_CC_CCCAM2,"%d: ECM caid %04x prov %04x sid %d pid %04x",cardnum,ecm->caId,ecm->provId,ecm->prgId,ecm->ecm_pid);
+  PRINTF(L_CC_CCCAM2,"ECM caid %04x prov %04x sid %d pid %04x",ecm->caId,ecm->provId,ecm->prgId,ecm->ecm_pid);
   int sctlen=SCT_LEN(data);
   if(sctlen>=256) {
     PRINTF(L_CC_CCCAM2,"ECM data length >=256 not supported by CCcam");
index 558efdc9a2f20f6699392ad015198134b19260ec..8453402820cbeea30a212db9942846555595e0db 100644 (file)
@@ -39,7 +39,7 @@ public:
   cCardClientGbox(const char *Name); 
   virtual bool Init(const char *CfgDir); 
   virtual bool Login(void);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
   }; 
  
 static cCardClientLinkReg<cCardClientGbox> __ncd("gbox");
@@ -76,7 +76,7 @@ int cCardClientGbox::GetMsg(int cmd, unsigned char *buff, int len)
   return n;
 }
 
-bool cCardClientGbox::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+bool cCardClientGbox::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
 {
   cMutexLock lock(this);
   if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
index d68a8f6968a4d545005d3e8b648ede7f1f4dafa6..5a084193090440b5c8d024f69120b24e3bea3b75 100644 (file)
@@ -189,7 +189,7 @@ public:
   virtual bool Init(const char *CfgDir);
   virtual bool Login(void);
   virtual bool CanHandle(unsigned short SysId);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *Cw);
   virtual bool ProcessEMM(int caSys, const unsigned char *data);
   };
 
@@ -470,7 +470,7 @@ bool cCardClientNewCamd::Login(void)
   return true;
 }
 
-bool cCardClientNewCamd::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw, int cardnum)
+bool cCardClientNewCamd::ProcessECM(const cEcmInfo *ecm, const unsigned char *data, unsigned char *cw)
 {
   cMutexLock lock(this);
   if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
index 5519d9439eb537671b20e2e998e9ee758a14b3f7..4b80078000090b1305193f1acd190dc029dd3b33 100644 (file)
@@ -50,7 +50,7 @@ public:
   virtual bool Init(const char *config);
   virtual bool Login(void);
   virtual bool CanHandle(unsigned short SysId);
-  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum);
+  virtual bool ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw);
   virtual bool ProcessEMM(int caSys, const unsigned char *data);
   };
 
@@ -218,7 +218,7 @@ bool cCardClientRadegast::Login(void)
   return true;
 }
 
-bool cCardClientRadegast::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw, int cardnum)
+bool cCardClientRadegast::ProcessECM(const cEcmInfo *ecm, const unsigned char *source, unsigned char *cw)
 {
   cMutexLock lock(this);
   if((!so.Connected() && !Login()) || !CanHandle(ecm->caId)) return false;
index 81b89aa7edb5b9ad0e188c637e5f602d2b3bfac6..0d0ca272b49e08ff0eaa2efc018f66ed4d6e26e5 100644 (file)
@@ -295,7 +295,7 @@ void cSystemIrd::ProcessEMM(int pid, int caid, const unsigned char *data)
   int slen=buffer[index-1]-5; // save packet length, 5 signature bytes
   int maxIndex=index+slen;
   if(maxIndex>n-5) {
-    PRINTF(L_SYS_EMM,"%d: bad packet length (%d > %d)",CardNum(),maxIndex,n-5);
+    PRINTF(L_SYS_EMM,"bad packet length (%d > %d)",maxIndex,n-5);
     maxIndex=n-5;
     }
   bool badnano=false;
@@ -372,13 +372,13 @@ void cSystemIrd::ProcessEMM(int pid, int caid, const unsigned char *data)
         break;
 
       default:
-        PRINTF(L_SYS_EMM,"%d: unhandled nano 0x%02x",CardNum(),nano);
+        PRINTF(L_SYS_EMM,"unhandled nano 0x%02x",nano);
         break;
       }
     index+=nlen+2;
     }
   if(badnano || index!=maxIndex) {
-    PRINTF(L_SYS_EMM,"%d: bad nano/bad paket",CardNum());
+    PRINTF(L_SYS_EMM,"bad nano/bad paket");
     return;
     }
 
index 0ef777158d2a8a7c7de6b571d05f2bbda7931e52..a45696a24c401d0b92a19f1671dd71e6b3541c0d 100644 (file)
@@ -868,7 +868,7 @@ void cSystemNagra::ProcessEMM(int pid, int caid, const unsigned char *buffer)
   const int id=buffer[10]*256+buffer[11];
   static const unsigned char tester[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x4B };
   if(memcmp(&buffer[3],tester,sizeof(tester)) || SCT_LEN(buffer)<(12+9+64)) {
-    PRINTF(L_SYS_EMM,"%d: not a valid EMM structure",CardNum());
+    PRINTF(L_SYS_EMM,"not a valid EMM structure");
     return;
     }
   const int pkey=(buffer[12]&3);
@@ -943,24 +943,24 @@ void cSystemNagra::ProcessEMM(int pid, int caid, const unsigned char *buffer)
         const int romNr=emmdata[i]&0x0F;
         if(!emu || !emu->Matches(romNr,id)) {
           delete emu; emu=0;
-          PRINTF(L_SYS_EMM,"%d: setting defaults for ROM %d",CardNum(),romNr);
+          PRINTF(L_SYS_EMM,"setting defaults for ROM %d",romNr);
           switch(romNr) {
             case 3:  emu=new cEmuRom3;  break;
             case 7:  emu=new cEmuRom7;  break;
             case 10: emu=new cEmuRom10; break;
             case 11: emu=new cEmuRom11; break;
-            default: PRINTF(L_SYS_EMM,"%d: unsupported ROM",CardNum()); return;
+            default: PRINTF(L_SYS_EMM,"unsupported ROM"); return;
             }
           if(!emu || !emu->Init(romNr,id)) {
             delete emu; emu=0;
-            PRINTF(L_SYS_EMM,"%d: initialization failed for ROM %d",CardNum(),romNr);
+            PRINTF(L_SYS_EMM,"initialization failed for ROM %d",romNr);
             return;
             }
           }
         unsigned char ki[2];
         if((gotKeys=emu->GetOpKeys(emmdata,ki,key0,key1))) {
           keyId=(ki[0]<<8)+ki[1];
-          PRINTF(L_SYS_EMM,"%d: got keys for %04X (ROM %d)",CardNum(),keyId,romNr);
+          PRINTF(L_SYS_EMM,"got keys for %04X (ROM %d)",keyId,romNr);
           }
         unsigned char select[3], pkset[3][15];
         select[0]=(keyId>>8)|0x01; // always high id for ECM RSA keys
@@ -968,7 +968,7 @@ void cSystemNagra::ProcessEMM(int pid, int caid, const unsigned char *buffer)
         select[2]=0; // type 0
         if(emu->GetPkKeys(&select[0],&pkset[0][0])) {
           int pkKeyId=((select[0]<<8)+select[1]);
-          PRINTF(L_SYS_EMM,"%d: got PK keys for %04X (ROM %d)",CardNum(),pkKeyId,romNr);
+          PRINTF(L_SYS_EMM,"got PK keys for %04X (ROM %d)",pkKeyId,romNr);
           for(int i=0; i<3; i++) {
             CreateRSAPair(pkset[i],0,e1,n1);
             FoundKey();
@@ -998,12 +998,12 @@ void cSystemNagra::ProcessEMM(int pid, int caid, const unsigned char *buffer)
         i+=10;
         if(++nrKeys==2) {
           gotKeys=true;
-          PRINTF(L_SYS_EMM,"%d: got keys for %04X (plain)",CardNum(),keyId);
+          PRINTF(L_SYS_EMM,"got keys for %04X (plain)",keyId);
           break;
           }
         }
       else {
-        PRINTF(L_SYS_EMM,"%d: ignored nano %02x",CardNum(),emmdata[i]);
+        PRINTF(L_SYS_EMM,"ignored nano %02x",emmdata[i]);
         break;
         }
       }
index d5e7fa343a4b12a379918a6db83891f17d891341..f8c80b13b4cc6441a34eab73b24f1ade50e24b08 100644 (file)
@@ -55,7 +55,11 @@ static const struct LogModule lm_sys = {
   };
 ADD_MODULE(L_SYS,lm_sys)
 
-// evil hack, but it's not worth to put much effort in a dead system ...
+// This system is dead.
+// Not worth to invest time to keep it compilig....
+
+#if 0
+
 static cTimeMs __time;
 #define time_ms() ((int)__time.Elapsed())
 
@@ -657,3 +661,5 @@ bool cSystemLinkShl::CanHandle(unsigned short SysId)
   SysId&=0xFFF0;
   return SYSTEM_CAN_HANDLE(SysId);
 }
+
+#endif //#if 0
index 1c7896a00b0bb6a94210bb30ef272a4e433cab5c..8b03a5b650c55146d9f5f00f4d3693fa5aa5d65a 100644 (file)
@@ -28,7 +28,7 @@
 #include "opentv.h"
 #include "st20.h"
 
-#include "sc.h"
+#include "global.h"
 #include "scsetup.h"
 #include "system-common.h"
 #include "filter.h"
@@ -127,7 +127,7 @@ cSatTimeHook::cSatTimeHook(cTransponderTime *Ttime)
 :cLogHook(HOOK_SATTIME,"sattime")
 {
   ttime=Ttime;
-  pids.AddPid(0x14,0x71,0xff,0x03);
+  pids.AddPid(0x14,0x70,0xfc);
   ttime->SetHasHandler(true);
 }
 
@@ -161,21 +161,19 @@ private:
   static cMutex mutex;
   static cSimpleList<cTransponderTime> list;
   //
-  int cardNum;
   cTransponderTime *ttime;
   //
   void CheckHandler(void);
 public:
-  cSatTime(int CardNum, int Source, int Transponder);
-  time_t Now(void);
+  cSatTime(int Source, int Transponder);
+  time_t Now(cSystem *sys);
   };
 
 cMutex cSatTime::mutex;
 cSimpleList<cTransponderTime> cSatTime::list;
 
-cSatTime::cSatTime(int CardNum, int Source, int Transponder)
+cSatTime::cSatTime(int Source, int Transponder)
 {
-  cardNum=CardNum;
   cMutexLock lock(&mutex);
   for(ttime=list.First(); ttime; ttime=list.Next(ttime))
     if(ttime->Is(Source,Transponder)) break;
@@ -185,24 +183,19 @@ cSatTime::cSatTime(int CardNum, int Source, int Transponder)
     PRINTF(L_SYS_TIME,"%x:%x: created new transpondertime",Source,Transponder);
     }
   else PRINTF(L_SYS_TIME,"%x:%x: using existing transpondertime",Source,Transponder);
-  CheckHandler();
-}
-
-time_t cSatTime::Now(void)
-{
-  CheckHandler();
-  return ttime ? ttime->Now() : -1;
 }
 
-void cSatTime::CheckHandler(void)
+time_t cSatTime::Now(cSystem *sys)
 {
   if(ttime) {
-    if(!cSoftCAM::TriggerHook(cardNum,HOOK_SATTIME) && !ttime->HasHandler()) {
+    if(!sys->TriggerHook(HOOK_SATTIME) && !ttime->HasHandler()) {
       cSatTimeHook *hook=new cSatTimeHook(ttime);
-      cSoftCAM::AddHook(cardNum,hook);
+      sys->AddHook(hook);
       PRINTF(L_SYS_TIME,"added hook");
       }
+    return ttime->Now();
     }
+  return -1;
 }
 
 // -- cOpenTVModule ------------------------------------------------------------
@@ -572,7 +565,7 @@ const cTpsKey *cTpsKeys::GetV2Key(int id)
   return 0;
 }
 
-void cTpsKeys::Check(time_t now, int cardnum)
+void cTpsKeys::Check(time_t now, cSystem *sys)
 {
   checkMutex.Lock();
   if(first==0 && last==0 && Count()>0)
@@ -591,9 +584,9 @@ void cTpsKeys::Check(time_t now, int cardnum)
   if(tpsAuMode==AU_STREAM && lastAu.Elapsed()>(nokey ? TPSAU_TIME/60 : TPSAU_TIME)) {
     if(ScSetup.AutoUpdate>0) {
       PRINTF(L_SYS_TPSAU,"TPS AU triggered");
-      if(!cSoftCAM::TriggerHook(cardnum,HOOK_TPSAU)) {
+      if(!sys->TriggerHook(HOOK_TPSAU)) {
         cTpsAuHook *hook=new cTpsAuHook;
-        cSoftCAM::AddHook(cardnum,hook);
+        sys->AddHook(hook);
         PRINTF(L_SYS_TPSAU,"TPS AU hook added");
         }
       }
@@ -989,7 +982,7 @@ void cTpsAuHook::Process(int pid, unsigned char *data)
             PRINTF(L_SYS_TPSAU,"got PMT pid %04x for SID %04x",pmtpid,AUSID);
             cPid *pid=pids.First();
             if(pid && pid->filter) {
-              pid->filter->Start(pmtpid,0x02,0xFF,0x00,false);
+              pid->filter->Start(pmtpid,0x02,0xFF);
               pid->filter->Flush();
               }
             else PRINTF(L_GEN_DEBUG,"internal: no pid/filter in cTpsAuHook/pat");
@@ -1010,7 +1003,7 @@ void cTpsAuHook::Process(int pid, unsigned char *data)
             PRINTF(L_SYS_TPSAU,"got AU pid %04x",aupid);
             cPid *pid=pids.First();
             if(pid && pid->filter) {
-              pid->filter->Start(aupid,0x87,0xFF,0x00,false);
+              pid->filter->Start(aupid,0x87,0xFF);
               pid->filter->Flush();
               }
             else PRINTF(L_GEN_DEBUG,"internal: no pid/filter in cTpsAuHook/pmt");
@@ -1161,17 +1154,17 @@ cTPS::~cTPS()
   delete sattime;
 }
 
-int cTPS::Decrypt(int cardNum, int Source, int Transponder, unsigned char *data, int len)
+int cTPS::Decrypt(cSystem *sys, int Source, int Transponder, unsigned char *data, int len)
 {
   if(!sattime) {
-    sattime=new cSatTime(cardNum,Source,Transponder);
+    sattime=new cSatTime(Source,Transponder);
     if(!sattime) {
       PRINTF(L_SYS_TPS,"failed to create time class");
       return -1;
       }
     }
-  time_t now=sattime->Now();
-  tpskeys.Check(now,cardNum);
+  time_t now=sattime->Now(sys);
+  tpskeys.Check(now,sys);
   if(now<0) return -1;
 
   const cTpsKey *k=tpskeys.GetKey(now);
index c8e40f8adbf6494aad0fef2ad20a5390589bac34..d8d9f3cb1a3eebe5f4bd994a0d82bb49907bc51f 100644 (file)
@@ -26,6 +26,7 @@
 #include "data.h"
 #include "crypto.h"
 
+class cSystem;
 class cSatTime;
 class cTpsAuHook;
 class cOpenTVModule;
@@ -61,7 +62,7 @@ private:
 public:
   cTPS(void);
   ~cTPS();
-  int Decrypt(int cardNum, int Source, int Transponder, unsigned char *data, int len);
+  int Decrypt(cSystem *sys, int Source, int Transponder, unsigned char *data, int len);
   void PostProc(unsigned char *cw);
   };
 
@@ -119,7 +120,7 @@ public:
   ~cTpsKeys();
   const cTpsKey *GetKey(time_t t);
   const cTpsKey *GetV2Key(int id);
-  void Check(time_t now, int cardnum);
+  void Check(time_t now, cSystem *sys);
   };
 
 extern cTpsKeys tpskeys;
index 01f5b5437503ea40a122843bec704efaf3e1fbfb..85fed321556e68a6871ece55f06daaff333d86d9 100644 (file)
@@ -385,7 +385,7 @@ bool cSystemViaccess::ProcessECM(const cEcmInfo *ecm, unsigned char *data)
   if(ecm->provId==0x007c00) { // TPS
     maxEcmTry=4;
     mayHaveTps=true;
-    int num=tps.Decrypt(CardNum(),ecm->source,ecm->transponder,nanos,len);
+    int num=tps.Decrypt(this,ecm->source,ecm->transponder,nanos,len);
     if(num<0) return false;
     nanos+=num; len-=num;
     }
@@ -479,7 +479,7 @@ void cSystemViaccess::ProcessEMM(int pid, int caid, const unsigned char *data)
                   numKeys++;
                   }
                 else {
-                  PRINTF(L_SYS_EMM,"%d: key length mismatch %d!=%d",CardNum(),plen,(int)sizeof(newKey[0]));
+                  PRINTF(L_SYS_EMM,"key length mismatch %d!=%d",plen,(int)sizeof(newKey[0]));
                   cnt=scanlen;
                   }
                 break;
index bdbd8e8bb9640224d39d691814f83adab7295a5a..e928f9db382729e6efd5a27390189b1a9d522832 100644 (file)
@@ -34,7 +34,8 @@ int main(int argc, char *argv[])
     printf("\n");
 
     max=5;
-    for(mode=0; mode<256; mode++) {
+    int mode=0;
+    //for(mode=0; mode<256; mode++) {
       for(mask=0; mask<256; mask++) {
         mam =mask &  (~mode);
         manm=mask & ~(~mode);
@@ -72,7 +73,7 @@ int main(int argc, char *argv[])
             }
           }
         }
-      }
+      //}
     printf("no exact settings found\n");
     exit(1);
     }
index b650687d5a2e17cca052f1814a503783be2e50c8..d338026c603d043ba47111dc0217afae3ddecfdd 100644 (file)
--- a/version.h
+++ b/version.h
@@ -25,7 +25,7 @@
 extern const char *ScVersion;
 
 // SC API version number for loading shared libraries
-#define SCAPIVERS 29
+#define SCAPIVERS 30
 #ifndef STATICBUILD
 #define SCAPIVERSTAG() int ScLibApiVersion=SCAPIVERS
 #else