]> www.vanbest.org Git - sasc-ng.git/commitdiff
smartcards: virtualise cardreader code
authorleslie <unknown>
Thu, 5 Mar 2009 04:16:27 +0000 (12:16 +0800)
committerleslie <unknown>
Thu, 5 Mar 2009 04:16:27 +0000 (12:16 +0800)
examples/cardslot.conf.example
sc.c
smartcard.c
smartcard.h
systems/sc-cryptoworks/sc-cryptoworks.c
systems/sc-irdeto/sc-irdeto.c
systems/sc-nagra/sc-nagra.c
systems/sc-videoguard2/sc-videoguard2.c
testing/Makefile
testing/compat.c

index b5d471ba421201c70e127c0a221ae7cef6b458be..b3d2fcf9d784ac0b5fff28f02a3374e3feb299ee 100644 (file)
 ;
 serial:/dev/ttyS0:0:0
 serial:/dev/ttyS1:1:0:3579545
+
+; emulated smartcard on dummy port. For testing/debugging purpose only!
+; The emulation code has to be enabled with the CARD_EMU define im smartcard.c
+;
+emuseca:
+emucrypto:
+emuirdeto:acs383
+emuirdeto:acs384
diff --git a/sc.c b/sc.c
index c7c92c006e6f017eb0d7947ee8ab2a2301814ecf..a3f61f46b686d958a0b1174b252466f8012532be 100644 (file)
--- a/sc.c
+++ b/sc.c
@@ -78,7 +78,7 @@
 #endif
 
 // SC API version number for loading shared libraries
-#define SCAPIVERS 21
+#define SCAPIVERS 22
 
 static cPlugin *ScPlugin;
 static cOpts *ScOpts, *LogOpts;
@@ -1011,17 +1011,12 @@ bool cScSetup::Ignore(unsigned short caid)
 bool cSoftCAM::Load(const char *cfgdir)
 {
   if(!Feature.KeyFile()) keys.Disable();
-  if(!Feature.SmartCard()) {
-    carddatas.Disable();
-    smartcards.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));
-  if(Feature.SmartCard())
-    smartcards.LaunchWatcher();
   return true;
 }
 
@@ -1030,7 +1025,6 @@ void cSoftCAM::Shutdown(void)
   cStructLoaders::Save(true);
   cSystems::Clean();
   smartcards.Shutdown();
-  carddatas.SafeClear();
   keys.SafeClear();
 }
 
index ef1bc51e86e73da51d87de946963ba46ed04bc39..45418db6465ee2cb72ce06b718148b479ccbf39f 100644 (file)
 #include "log-core.h"
 
 #define ISO_FREQ 3571200 // Hz
+#define ISO_BAUD 9600
 
-//#define SER_EMU   // use serial emulation (select one of the following)
-//#define EMU_SECA  // fake Seca card
-//#define EMU_IRD   // fake Irdeto/Beta card
-//#define EMU_IRD_384 // fake ACS 384, if undefined ACS 383
-//#define EMU_CRYPTO // fake Cryptoworks card
+//#define CARD_EMU     // include smartcard emulation code
 //#define NO_PTS_PROTO // disable PTS protocol (baudrate changes)
 
-struct BaudRates {
-  int real;
-  speed_t apival;
-  };
+// -- cSmartCardSlot -----------------------------------------------------------
 
-static const struct BaudRates BaudRateTab[] = {
-  {   9600, B9600   },
-  {  19200, B19200  },
-  {  38400, B38400  },
-  {  57600, B57600  },
-  { 115200, B115200 },
-  { 230400, B230400 }
+class cSmartCardSlot : private cThread, public cStructItem {
+private:
+  cSmartCard *card;
+  int usecount, cardid;
+  bool firstRun, needsReset, dead, ready;
+  cMutex mutex;
+  cCondVar cond;
+  //
+  void SetCard(cSmartCard *c, int cid=0);
+  bool CardReset(void);
+protected:
+  virtual bool DeviceOpen(const char *cfg)=0;
+  virtual void DeviceClose(void) {}
+  virtual bool DeviceSetMode(int mode, int baud)=0;
+  virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0)=0;
+  virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0)=0;
+  virtual void DeviceToggleReset(void)=0;
+  virtual bool DevicePTS(void)=0;
+  virtual bool DeviceIsInserted(void)=0;
+  virtual int DeviceCurrentMode(void)=0;
+  //
+  virtual void Action(void);
+  // possibly virtual
+  bool Reset(void);
+  //
+  int Procedure(unsigned char ins, int restLen);
+  int Read(unsigned char *data, int len, int to=0);
+  int Write(const unsigned char *data, int len);
+  bool Test(bool res);
+  void Invert(unsigned char *data, int n);
+  bool ParseAtr(void);
+  //
+  int slotnum, clock;
+  struct Atr atr;
+  bool localecho;
+public:
+  cSmartCardSlot(void);
+  virtual ~cSmartCardSlot();
+  bool Setup(int num, const char *cfg);
+  void TriggerReset(void) { needsReset=true; }
+  bool HaveCard(int id);
+  cSmartCard *LockCard(int id);
+  void ReleaseCard(cSmartCard *sc);
+  void GetCardIdStr(char *str, int len);
+  bool GetCardInfoStr(char *str, int len);
+  int SlotNum(void) { return slotnum; }
+  // possibly virtual
+  bool IsoRead(const unsigned char *cmd, unsigned char *data);
+  bool IsoWrite(const unsigned char *cmd, const unsigned char *data);
+  int RawRead(unsigned char *data, int len, int to=0);
+  int RawWrite(const unsigned char *data, int len);
   };
 
-// -- cSerial ------------------------------------------------------------------
+static const char *serModes[] = { 0,"8e2","8o2","8n2" };
+
+cSmartCardSlot::cSmartCardSlot(void)
+{
+  card=0; usecount=0; slotnum=-1; clock=ISO_FREQ;
+  firstRun=true; needsReset=false; dead=false; ready=false; localecho=true;
+}
+
+cSmartCardSlot::~cSmartCardSlot()
+{
+  Cancel(3);
+  SetCard(0);
+  DeviceClose();
+}
+
+bool cSmartCardSlot::Setup(int num, const char *cfg)
+{
+  slotnum=num;
+  SetDescription("CardSlot %d watcher",slotnum);
+  if(DeviceOpen(cfg)) {
+    firstRun=true;
+    Start();
+    return true;
+    }
+  return false;
+}
+
+bool cSmartCardSlot::HaveCard(int id)
+{
+  cMutexLock lock(&mutex);
+  while(Running() && firstRun) cond.Wait(mutex);
+  return ready && card && cardid==id;
+}
+
+cSmartCard *cSmartCardSlot::LockCard(int id)
+{
+  mutex.Lock();
+  while(Running() && firstRun) cond.Wait(mutex);
+  if(ready && card && cardid==id) {
+    usecount++;
+    mutex.Unlock();
+    card->Lock();
+    if(DeviceIsInserted() && card->CardUp() && !needsReset) return card;
+    // if failed, unlock the card and decrement UseCount
+    card->Unlock();
+    mutex.Lock();
+    usecount--;
+    cond.Broadcast();
+    }
+  mutex.Unlock();
+  return 0;
+}
+
+void cSmartCardSlot::ReleaseCard(cSmartCard *sc)
+{
+  if(card==sc) {
+    card->Unlock();
+    mutex.Lock();
+    usecount--;
+    cond.Broadcast();
+    mutex.Unlock();
+    }
+}
+
+void cSmartCardSlot::GetCardIdStr(char *str, int len)
+{
+  mutex.Lock();
+  if(ready && card && !card->GetCardIdStr(str,len)) {
+    for(cSmartCardLink *scl=smartcards.First(); scl; smartcards.Next(scl)) {
+      if(scl->Id()==cardid) {
+        strn0cpy(str,scl->Name(),len);
+        break;
+        }
+      }
+    }
+  mutex.Unlock();
+}
+
+bool cSmartCardSlot::GetCardInfoStr(char *str, int len)
+{
+  mutex.Lock();
+  bool res=false;
+  if(ready && card) res=card->GetCardInfoStr(str,len);
+  mutex.Unlock();
+  return res;
+}
+
+void cSmartCardSlot::SetCard(cSmartCard *c, int cid)
+{
+  mutex.Lock();
+  while(usecount) cond.Wait(mutex);
+  if(card!=c) delete card;
+  card=c; cardid=cid; ready=(card!=0); needsReset=dead=false;
+  mutex.Unlock();
+}
+
+void cSmartCardSlot::Action(void)
+{
+  while(Running()) {
+    if(card) {
+      card->Lock();
+      if(!DeviceIsInserted()) {
+        card->Unlock();
+        PRINTF(L_CORE_SC,"%d: card removed (usecount=%d)",slotnum,usecount);
+        SetCard(0);
+        }
+      else if(needsReset) {
+        PRINTF(L_CORE_SC,"%d: card reset requested",slotnum);
+        int mode=DeviceCurrentMode()&SM_MASK;
+        if(!DeviceSetMode(mode,ISO_BAUD)
+            || !CardReset()
+            || !card->Setup(this,mode,&atr)) {
+          card->Unlock();
+          PRINTF(L_CORE_SC,"%d: card re-init failed",slotnum);
+          SetCard(0); dead=true;
+          }
+        }
+      if(card) card->Unlock();
+      }
+    else if(DeviceIsInserted()) {
+      if(!dead) {
+        PRINTF(L_CORE_SC,"%d: new card inserted",slotnum);
+        for(int mode=SM_NONE+1 ; mode<SM_MAX ; mode++) {
+          if(DeviceSetMode(mode,ISO_BAUD)) {
+            if(CardReset()) {
+              for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl)) {
+                if(!Running()) goto done;
+                PRINTF(L_CORE_SC,"%d: checking for %s card",slotnum,scl->Name());
+                card=scl->Create();
+                if(card && card->Setup(this,mode,&atr)) {
+                  SetCard(card,scl->Id());
+                  goto done; // ugly, any better solution?
+                  }
+                delete card; card=0;
+                }
+              PRINTF(L_CORE_SC,"%d: no card handler found",slotnum);
+              }
+            else PRINTF(L_CORE_SC,"%d: reset/atr error",slotnum);
+            }
+          else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slotnum,serModes[mode]);
+          }
+        dead=true;
+        PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slotnum);
+        }
+      }
+    else {
+      if(dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slotnum);
+      dead=false;
+      }
+done:
+    if(firstRun) {
+      mutex.Lock();
+      cond.Broadcast();
+      firstRun=false;
+      mutex.Unlock();
+      }
+    cCondWait::SleepMs(300);
+    }
+}
+
+bool cSmartCardSlot::Reset(void)
+{
+  PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",slotnum,serModes[DeviceCurrentMode()]);
+  DeviceToggleReset();
+  cCondWait::SleepMs(100);
+  DeviceToggleReset();
+  int r=DeviceRead(atr.atr,-MAX_ATR_LEN,800,2000);
+  atr.atrLen=r;
+  if(r>0) LDUMP(L_CORE_SC,atr.atr,r,"%d: <- ATR len=%d:",slotnum,r);
+  return r>=2;
+}
+
+bool cSmartCardSlot::CardReset(void)
+{
+  if(!Reset() || !ParseAtr()) return false;
+  if((atr.F!=372 || atr.D!=1.0) && !DevicePTS()) {
+    // reset card again and continue without PTS
+    if(!Reset() || !ParseAtr()) return false;
+    }
+  return true;
+}
+
+void cSmartCardSlot::Invert(unsigned char *data, int n)
+{
+  static const unsigned char swaptab[] =  { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 };
+  for(int i=n-1; i>=0; i--)
+    data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4];
+}
+
+int cSmartCardSlot::Read(unsigned char *data, int len, int to)
+{
+  int r=DeviceRead(data,len,card->cfg->serTO,to);
+  if(atr.convention==SM_INDIRECT && r>0) Invert(data,r);
+  return r;
+}
+
+int cSmartCardSlot::Write(const unsigned char *data, int len)
+{
+  unsigned char *tmp=AUTOMEM(len);
+  if(atr.convention==SM_INDIRECT) {
+    memcpy(tmp,data,len);
+    Invert(tmp,len);
+    data=tmp;
+    }
+  int r=DeviceWrite(data,len,card->cfg->serDL);
+  if(r>0 && localecho) {
+    unsigned char *buff=AUTOMEM(r);
+    int rr=DeviceRead(buff,r,card->cfg->serTO);
+    if(rr<0) r=rr;
+    }
+  return r;
+}
+
+int cSmartCardSlot::Procedure(unsigned char ins, int restLen)
+{
+  int r;
+  unsigned char buff;
+  LBSTARTF(L_CORE_SC);
+  LBPUT("%d: <- PROC: ",slotnum);
+  do {
+    do {
+      if(Read(&buff,1,card->cfg->workTO)<=0) return -1;
+      LBPUT("%02x ",buff);
+      } while(buff==0x60);
+
+    if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2
+      card->sb[0]=buff;
+      if(Read(&buff,1)<=0) return -1;
+      LBPUT("%02x",buff);
+      card->sb[1]=buff;
+      return 0;
+      }
+    else {
+      if((buff&0xFE)==(ins&0xFE)) r=restLen;
+      else if((~buff&0xFE)==(ins&0xFE)) r=1;
+      else {
+        LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins);
+        return -1;
+        }
+      if(r>restLen) {
+        LBPUT("data overrun r=%d restLen=%d",r,restLen);
+        return -1;
+        }
+      }
+    } while(r==0);
+  LBEND();
+  return r;
+}
+
+bool cSmartCardSlot::Test(bool res)
+{
+ if(!res) {
+   TriggerReset();
+   PRINTF(L_CORE_SC,"%d: reset triggered",slotnum);
+   }
+ return res;
+}
+
+bool cSmartCardSlot::IsoRead(const unsigned char *cmd, unsigned char *data)
+{
+  LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
+  if(Write(cmd,CMD_LEN)<0) return Test(false);
+  int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256;
+  int len=0;
+  while(1) {
+    int r=Procedure(cmd[INS_IDX],tr-len);
+    if(r<=0) return Test(r==0);
+    if(Read(data+len,r)<0) return Test(false);
+    LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",slotnum);
+    len+=r;
+    }
+}
+
+bool cSmartCardSlot::IsoWrite(const unsigned char *cmd, const unsigned char *data)
+{
+  LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",slotnum);
+  if(Write(cmd,CMD_LEN)<0) return Test(false);
+  int len=0;
+  while(1) {
+    int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len);
+    if(r<=0) return Test(r==0);
+    if(Write(data+len,r)<0) return Test(false);
+    LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",slotnum);
+    len+=r;
+    }
+}
+
+int cSmartCardSlot::RawRead(unsigned char *data, int len, int to)
+{
+  int r=Read(data,len,to);
+  if(r<0) Test(false);
+  return r;
+}
+
+int cSmartCardSlot::RawWrite(const unsigned char *data, int len)
+{
+  int r=Write(data,len);
+  if(r<0) Test(false);
+  return r;
+}
+
+#define NEED(x) { if(len+(x)>atr.atrLen) { LBPUT("SHORT ATR"); return false; } }
+
+bool cSmartCardSlot::ParseAtr(void)
+{
+  // default values
+  atr.histLen=0; atr.T=0; atr.F=372; atr.D=1.0; atr.N=0; atr.WI=10;
+  atr.BWI=4; atr.CWI=0; atr.Tspec=-1;
+
+  static const int Ftable[16] = {
+    372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0
+    };
+  static const float Dtable[16] = {
+    0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0,
+    0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625
+    };
+
+  const unsigned char *rawatr=atr.atr;
+  if(rawatr[0]==0x03) {
+    PRINTF(L_CORE_SC,"%d: indirect convention detected",slotnum);
+    Invert(atr.atr,atr.atrLen);
+    atr.convention=SM_INDIRECT;
+    }
+  else if(rawatr[0]==0x3B) {
+    PRINTF(L_CORE_SC,"%d: direct convention detected",slotnum);
+    atr.convention=SM_DIRECT;
+    }
+  else {
+    PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",slotnum,rawatr[0]);
+    return false;
+    }
 
-class cSerial {
+  // TS TO
+  atr.histLen=rawatr[1]&0x0F;
+  int Y=rawatr[1]&0xF0, i=1, len=2;
+  LBSTARTF(L_CORE_SC);
+  LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",slotnum,rawatr[0],atr.histLen,i,Y);
+  do {
+    if(Y&0x10) { // TAi
+      NEED(1);
+      LBPUT("TA%d=%02x ",i,rawatr[len]);
+      if(i==1) {
+        atr.TA1=rawatr[len];
+        atr.F=Ftable[(rawatr[len]>>4)&0x0F];
+        atr.D=Dtable[ rawatr[len]    &0x0F];
+        LBPUT("F=%d D=%f ",atr.F,atr.D);
+        }
+      else if(i==2) {
+        atr.Tspec=rawatr[len]&0x0F;
+        LBPUT("Tspec=%d ",atr.Tspec);
+        }
+      else if(i==3) {
+        LBPUT("IFSC=%d ",rawatr[len]);
+        }
+      len++;
+      }
+    if(Y&0x20) { // TBi
+      NEED(1);
+      LBPUT("TB%d=%02x ",i,rawatr[len]);
+      if(i==3) {
+        atr.BWI=(rawatr[len]>>4)&0x0F;
+        atr.CWI=rawatr[len]&0x0F;
+        LBPUT("BWI=%d CWI=%d ",atr.BWI,atr.CWI);
+        }
+      len++;
+      }
+    if(Y&0x40) { // TCi
+      NEED(1);
+      LBPUT("TC%d=%02x ",i,rawatr[len]);
+      if(i==1) {
+        atr.N=rawatr[len];
+        LBPUT("N=%d ",atr.N);
+        }
+      else if(i==2) {
+        atr.WI=rawatr[len];
+        LBPUT("WI=%d ",atr.WI);
+        }
+      else if(i==3) {
+        LBPUT("CHK=%s ",rawatr[len]&1 ? "CRC16":"LRC");
+        }
+      len++;
+      }
+    if(Y&0x80) { // TDi
+      NEED(1);
+      LBPUT("TD%d=%02x ",i,rawatr[len]);
+      if(i==1) {
+        atr.T=rawatr[len]&0x0F;
+        LBPUT("T=%d ",atr.T);
+        }
+      else {
+        LBPUT("Tn=%d ",rawatr[len]&0x0F);
+        }
+      Y=rawatr[len]&0xF0;
+      len++;
+      }
+    else Y=0;
+    i++;
+    LBPUT("Y%d=%02x ",i,Y);
+    } while(Y);
+  NEED(atr.histLen);
+  LBEND();
+
+  LBSTART(L_CORE_SC);
+  LBPUT("%d: historical:",slotnum);
+  for(int i=0; i<atr.histLen; i++) LBPUT(" %02x",rawatr[len+i]);
+  LBFLUSH();
+  LBPUT("%d: historical: '",slotnum);
+  for(int i=0; i<atr.histLen; i++) LBPUT("%c",isprint(rawatr[len+i]) ? rawatr[len+i] : '.');
+  LBEND();
+
+  memcpy(atr.hist,&rawatr[len],atr.histLen);
+  len+=atr.histLen;
+
+  // TCK
+  if(atr.T!=0 && len+1<=atr.atrLen) {
+    len++;
+    unsigned char cs=XorSum(rawatr+1,len-1);
+    // according to the ISO the initial TS byte isn't checksumed, but
+    // some cards do so. In this case the checksum is equal TS.
+    if(cs==0) PRINTF(L_CORE_SC,"%d: atr checksum ok",slotnum);
+    else if(cs==rawatr[0]) PRINTF(L_CORE_SC,"iso: %d: atr checksum is TS (not ISO compliant)",slotnum);
+    else {
+      PRINTF(L_CORE_SC,"%d: atr checksum FAILED (cs:%02x)",slotnum,cs);
+      return false;
+      }
+    }
+  else PRINTF(L_CORE_SC,"%d: atr checksum not given/not required",slotnum);
+
+  if(atr.atrLen>len) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",slotnum,atr.atrLen,len);
+  atr.wwt=960*atr.WI*atr.F/(clock/1000);
+  atr.bwt=(int)(960*(float)(1<<atr.BWI)*372/(clock/1000));
+  PRINTF(L_CORE_SC,"%d: indicated wwt(T0)=%d ms, bwt(T1)=%d ms (at %.4f MHz)",slotnum,atr.wwt,atr.bwt,(float)clock/1000000);
+  return true;
+}
+
+#undef NEED
+
+// -- cSmartCardSlots ----------------------------------------------------------
+
+class cSmartCardSlots : public cStructListPlain<cSmartCardSlot> {
+friend class cSmartCardSlotLink;
 private:
-  char *devName;
-  int fd;
-  int currMode, statInv;
-  bool invRST;
+  static cSmartCardSlotLink *first;
   //
-  speed_t FindBaud(int baud);
-#ifdef SER_EMU
-  unsigned char devBuff[1024], nextSW[SB_LEN];
-  int buffCount, dataLen, record;
-  bool cmdStart, rts, dsr, flag;
-  int remTime;
-#endif
+  static void Register(cSmartCardSlotLink *scl);
+protected:
+  virtual bool ParseLinePlain(const char *line);
 public:
-  cSerial(const char *DevName, bool invCD, bool InvRST);
-  ~cSerial();
-  bool Open(void);
-  bool SetMode(int mode, int baud=9600);
-  int CurrentMode(void) const { return currMode; }
-  void Flush(void);
-  int Read(unsigned char *mem, int len, int timeout, int initialTimeout=0);
-  int Write(const unsigned char *mem, int len, int delay=0);
-  void ToggleRTS(void);
-  bool CheckCAR(void);
-  void Close(void);
-  const char *DeviceName(void) const { return devName; }
+  cSmartCardSlots(void);
+  cSmartCardSlot *GetSlot(int num);
+  cSmartCardSlot *FirstSlot(void);
+  void Release(void);
   };
 
-cSerial::cSerial(const char *DevName, bool invCD, bool InvRST)
+cSmartCardSlotLink *cSmartCardSlots::first=0;
+
+static cSmartCardSlots cardslots;
+
+// -- cSmartCardSlotLink -------------------------------------------------------
+
+class cSmartCardSlotLink {
+public:
+  cSmartCardSlotLink *next;
+  const char *name;
+public:
+  cSmartCardSlotLink(const char *Name);
+  virtual ~cSmartCardSlotLink() {}
+  virtual cSmartCardSlot *Create(void)=0;
+  };
+
+template<class LL> class cSmartCardSlotLinkReg : public cSmartCardSlotLink {
+public:
+  cSmartCardSlotLinkReg(const char *Name):cSmartCardSlotLink(Name) {}
+  virtual cSmartCardSlot *Create(void) { return new LL; }
+  };
+
+cSmartCardSlotLink::cSmartCardSlotLink(const char *Name)
+{
+  name=Name;
+  cSmartCardSlots::Register(this);
+}
+
+// -- cSmartCardSlots ----------------------------------------------------------
+
+cSmartCardSlots::cSmartCardSlots(void)
+:cStructListPlain<cSmartCardSlot>("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE)
+{}
+
+void cSmartCardSlots::Register(cSmartCardSlotLink *scl)
 {
-  devName=strdup(DevName);
-  statInv=invCD ? TIOCM_CAR:0;
-  invRST=InvRST;
-  fd=-1; currMode=SM_NONE;
+  PRINTF(L_CORE_DYN,"registering cardslot type %s",scl->name);
+  scl->next=first;
+  first=scl;
 }
 
-cSerial::~cSerial()
+cSmartCardSlot *cSmartCardSlots::GetSlot(int num)
 {
-  Close();
-  free(devName);
+  ListLock(false);
+  for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
+    if(slot->SlotNum()==num) return slot;
+  return 0;
 }
 
-#ifndef SER_EMU
+cSmartCardSlot *cSmartCardSlots::FirstSlot(void)
+{
+  ListLock(false);
+  return First();
+}
 
-bool cSerial::Open(void)
+void cSmartCardSlots::Release(void)
 {
-  PRINTF(L_CORE_SERIAL,"%s: open serial port",devName);
-  fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY);
-  if(fd>=0) {
-    PRINTF(L_CORE_SERIAL,"%s: set DTR/RTS",devName);
-    unsigned int modembits;
-    modembits=TIOCM_DTR; CHECK(ioctl(fd, TIOCMBIS, &modembits));
-    modembits=TIOCM_RTS; CHECK(ioctl(fd, invRST?TIOCMBIS:TIOCMBIC, &modembits));
-    PRINTF(L_CORE_SERIAL,"%s: init done",devName);
-    return true;
+  ListUnlock();
+}
+
+bool cSmartCardSlots::ParseLinePlain(const char *line)
+{
+  char type[32];
+  int num;
+  if(sscanf(line,"%31[^:]:%n",type,&num)==1) {
+    for(cSmartCardSlotLink *scs=first; scs; scs=scs->next) {
+      if(!strcasecmp(type,scs->name)) {
+        cSmartCardSlot *slot=scs->Create();
+        if(slot) {
+          if(slot->Setup(Count(),&line[num])) {
+            Add(slot);
+            return true;
+            }
+          delete slot;
+          }
+        else PRINTF(L_GEN_ERROR,"failed to create cardslot");
+        return false;
+        }
+      }
+    PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type);
+    }
+  return false;
+}
+
+// -- cSmartCardSlotSerial -----------------------------------------------------
+
+class cSmartCardSlotSerial : public cSmartCardSlot {
+private:
+  char devName[256];
+  int fd;
+  int currMode, statInv, invRST;
+  //
+  void Flush(void);
+  speed_t FindBaud(int baud);
+protected:
+  virtual bool DeviceOpen(const char *cfg);
+  virtual void DeviceClose(void);
+  virtual bool DeviceSetMode(int mode, int baud);
+  virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0);
+  virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+  virtual void DeviceToggleReset(void);
+  virtual bool DevicePTS(void);
+  virtual bool DeviceIsInserted(void);
+  virtual int DeviceCurrentMode(void) { return currMode; }
+public:
+  cSmartCardSlotSerial(void);
+  };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotSerial> __scs_serial("serial");
+
+cSmartCardSlotSerial::cSmartCardSlotSerial(void)
+{
+  fd=-1; statInv=0; invRST=false; currMode=SM_NONE;
+}
+
+bool cSmartCardSlotSerial::DeviceOpen(const char *cfg)
+{
+  int invCD=0;
+  if(sscanf(cfg,"%255[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) {
+    statInv=invCD ? TIOCM_CAR:0;
+    PRINTF(L_CORE_SERIAL,"%s: open serial port",devName);
+    fd=open(devName,O_RDWR|O_NONBLOCK|O_NOCTTY);
+    if(fd>=0) {
+      PRINTF(L_CORE_SERIAL,"%s: set DTR/RTS",devName);
+      unsigned int modembits;
+      modembits=TIOCM_DTR; CHECK(ioctl(fd, TIOCMBIS, &modembits));
+      modembits=TIOCM_RTS; CHECK(ioctl(fd, invRST?TIOCMBIS:TIOCMBIC, &modembits));
+      PRINTF(L_CORE_SERIAL,"%s: init done",devName);
+      PRINTF(L_CORE_LOAD,"cardslot: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)",
+                devName,slotnum,invCD?"inverse":"normal",invRST?"inverse":"normal",clock);
+      return true;
+      }
+    else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));
     }
-  else PRINTF(L_GEN_ERROR,"%s: open failed: %s",devName,strerror(errno));
+  else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type 'serial'");
   return false;
 }
 
-void cSerial::Close(void)
+void cSmartCardSlotSerial::DeviceClose(void)
 {
   if(fd>=0) {
     PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);
@@ -133,8 +700,18 @@ void cSerial::Close(void)
     }
 }
 
-speed_t cSerial::FindBaud(int baud)
+void cSmartCardSlotSerial::Flush(void)
 {
+  if(fd>=0) CHECK(tcflush(fd,TCIOFLUSH));
+}
+
+speed_t cSmartCardSlotSerial::FindBaud(int baud)
+{
+  static const struct BaudRates { int real; speed_t apival; } BaudRateTab[] = {
+    {   9600, B9600   }, {  19200, B19200  }, {  38400, B38400  },
+    {  57600, B57600  }, { 115200, B115200 }, { 230400, B230400 }
+    };
+
   for(int i=0; i<(int)(sizeof(BaudRateTab)/sizeof(struct BaudRates)); i++) {
     int b=BaudRateTab[i].real;
     int d=((b-baud)*10000)/b;
@@ -147,13 +724,13 @@ speed_t cSerial::FindBaud(int baud)
   return B0;
 }
 
-bool cSerial::SetMode(int mode, int baud)
+bool cSmartCardSlotSerial::DeviceSetMode(int mode, int baud)
 {
   if(fd>=0) {
     speed_t bconst=FindBaud(baud);
     bool custom=false;
     if(bconst==B0) { custom=true; bconst=B38400; }
-    
+
     struct termios tio;
     memset(&tio,0,sizeof(tio));
     LBSTARTF(L_CORE_SERIAL);
@@ -165,7 +742,7 @@ bool cSerial::SetMode(int mode, int baud)
     cfsetispeed(&tio,bconst);
     cfsetospeed(&tio,bconst);
     switch(mode&SM_MASK) {
-      case SM_8E2: 
+      case SM_8E2:
         LBPUT("8e%d",(mode&SM_1SB)?1:2);
         tio.c_cflag |= PARENB; break;
       case SM_8N2:
@@ -211,13 +788,7 @@ bool cSerial::SetMode(int mode, int baud)
   return false;
 }
 
-void cSerial::Flush(void)
-{
-  if(fd>=0)
-    CHECK(tcflush(fd,TCIOFLUSH));
-}
-
-int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout)
+int cSmartCardSlotSerial::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout)
 {
   PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d:%d",devName,len,timeout,initialTimeout);
   bool incomplete=false;
@@ -254,7 +825,7 @@ int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout)
   return n;
 }
 
-int cSerial::Write(const unsigned char *mem, int len, int delay)
+int cSmartCardSlotSerial::DeviceWrite(const unsigned char *mem, int len, int delay)
 {
   PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
   HEXDUMP(L_CORE_SERIAL,mem,len,"%s: write data",devName);
@@ -286,7 +857,7 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
   return n;
 }
 
-void cSerial::ToggleRTS(void)
+void cSmartCardSlotSerial::DeviceToggleReset(void)
 {
   int mask=0;
   if(ioctl(fd,TIOCMGET,&mask)<0) { LOG_ERROR; return; }
@@ -296,7 +867,56 @@ void cSerial::ToggleRTS(void)
   Flush();
 }
 
-bool cSerial::CheckCAR(void)
+bool cSmartCardSlotSerial::DevicePTS(void)
+{
+  int baud=(int)((float)clock*atr.D/atr.F);
+  PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",slotnum,baud);
+
+  if(atr.Tspec<0) {
+    PRINTF(L_CORE_SC,"%d: negotiable mode",slotnum);
+#ifdef NO_PTS_PROTO
+    PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",slotnum);
+    return true;
+#else
+    unsigned char req[4], conf[16];
+    req[0]=0xFF;
+    req[1]=0x10 | atr.T;
+    req[2]=atr.TA1;
+    req[3]=XorSum(req,3);
+    LDUMP(L_CORE_SC,req,4,"%d: PTS request:",slotnum);
+    if(DeviceWrite(req,4)!=4) {
+      PRINTF(L_CORE_SC,"%d: PTS request, write failed",slotnum);
+      return false;
+      }
+    if(DeviceRead(conf,4,100,100)!=4) {
+      PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",slotnum);
+      return false;
+      }
+    int n=DeviceRead(conf,-16,200,1000);
+    if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",slotnum);
+    if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) {
+      PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",slotnum);
+      return false;
+      }
+    if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) {
+      PRINTF(L_CORE_SC,"%d: PTS not confirmed",slotnum);
+      return false;
+      }
+#endif // NO_PTS_PROTO
+    }
+  else
+    PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",slotnum,atr.Tspec);
+
+  int mode=DeviceCurrentMode();
+  if(atr.N==255) mode|=SM_1SB;
+  if(!DeviceSetMode(mode,baud)) {
+    PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",slotnum,baud);
+    return false;
+    }
+  return true;
+}
+
+bool cSmartCardSlotSerial::DeviceIsInserted(void)
 {
   int status=0;
   if(ioctl(fd,TIOCMGET,&status)<0) { LOG_ERROR; return false; }
@@ -311,54 +931,73 @@ bool cSerial::CheckCAR(void)
   return !(status & TIOCM_CAR);
 }
 
-#else //SER_EMU
+#ifdef CARD_EMU
+
+// -- cSmartCardSlotEmuGeneric -------------------------------------------------
+
+#define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); }
+#define PUSHB(b)      { devBuff[buffCount++]=(b); }
+
+class cSmartCardSlotEmuGeneric : public cSmartCardSlot {
+private:
+  int currMode;
+protected:
+  char devName[256];
+  unsigned char devBuff[1024], nextSW[SB_LEN];
+  int buffCount, dataLen, record;
+  bool cmdStart, rts, dsr, flag;
+  time_t remTime;
+  //
+  virtual bool DeviceOpen(const char *cfg);
+  virtual void DeviceClose(void);
+  virtual bool DeviceSetMode(int mode, int baud);
+  virtual int DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout=0);
+  virtual void DeviceToggleReset(void);
+  virtual bool DevicePTS(void);
+  virtual bool DeviceIsInserted(void);
+  virtual int DeviceCurrentMode(void) { return currMode; }
+  //
+  virtual void EmuPushAtr(void)=0;
+  void Flush(void);
+public:
+  cSmartCardSlotEmuGeneric(void);
+  };
 
-//
-// emulator for a serial phoenix interface
-// (activate in smartcard.h)
-//
+cSmartCardSlotEmuGeneric::cSmartCardSlotEmuGeneric(void)
+{
+  currMode=SM_NONE;
+}
 
-bool cSerial::Open(void)
+bool cSmartCardSlotEmuGeneric::DeviceOpen(const char *cfg)
 {
-  PRINTF(L_CORE_SERIAL,"serial: open serial port %s (emulator)",devName);
-  PRINTF(L_CORE_SERIAL,"serial: init done");
-  fd=1; buffCount=0; cmdStart=true; rts=false; flag=false;
+  PRINTF(L_CORE_SERIAL,"%s: open serial port (emulator)",devName);
+  PRINTF(L_CORE_SERIAL,"%s: init done",devName);
+  buffCount=0; cmdStart=true; rts=false; flag=false;
   remTime=time(0); dsr=true;
+  PRINTF(L_CORE_LOAD,"cardslot: added emulated port %s as port %d",devName,slotnum);
   return true;
 }
 
-void cSerial::Close(void)
+void cSmartCardSlotEmuGeneric::DeviceClose(void)
 {
-  if(fd>=0) {
-    PRINTF(L_CORE_SERIAL,"serial: shutting down ... ");
-    fd=-1;
-    PRINTF(L_CORE_SERIAL,"done");
-    }
+  PRINTF(L_CORE_SERIAL,"%s: shutting down",devName);
 }
 
-speed_t cSerial::FindBaud(int baud)
+void cSmartCardSlotEmuGeneric::Flush(void)
 {
-  return B0;
+  buffCount=0;
 }
 
-bool cSerial::SetMode(int mode, int baud)
+bool cSmartCardSlotEmuGeneric::DeviceSetMode(int mode, int baud)
 {
   currMode=mode;
   Flush();
   return true;
 }
 
-void cSerial::Flush(void)
-{
-  buffCount=0;
-}
-
-#define PUSH(mem,len) { memcpy(devBuff+buffCount,(mem),(len)); buffCount+=(len); }
-#define PUSHB(b)      { devBuff[buffCount++]=(b); }
-
-int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout)
+int cSmartCardSlotEmuGeneric::DeviceRead(unsigned char *mem, int len, int timeout, int initialTimeout)
 {
-  PRINTF(L_CORE_SERIAL,"serial: read len=%d timeout=%d",len,timeout);
+  PRINTF(L_CORE_SERIAL,"%s: read len=%d timeout=%d",devName,len,timeout);
   if(len<0) {
     len=-len;
     if(buffCount<len) len=buffCount;
@@ -370,13 +1009,56 @@ int cSerial::Read(unsigned char *mem, int len, int timeout, int initialTimeout)
   return len;
 }
 
-int cSerial::Write(const unsigned char *mem, int len, int delay)
+void cSmartCardSlotEmuGeneric::DeviceToggleReset(void)
+{
+  rts=!rts;
+  if(!rts) {
+    EmuPushAtr();
+    PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now off",devName);
+    }
+  else { PRINTF(L_CORE_SERIAL,"%s: toggle RTS, now on",devName); }
+}
+
+bool cSmartCardSlotEmuGeneric::DevicePTS(void)
+{
+  return true;
+}
+
+bool cSmartCardSlotEmuGeneric::DeviceIsInserted(void)
+{
+#if 0
+  if(time(0)>=remTime+30) {
+    dsr=!dsr;
+    remTime=time(0);
+    }
+#endif
+  return dsr;
+}
+
+// -- cSmartCardSlotEmuSeca ----------------------------------------------------
+
+class cSmartCardSlotEmuSeca : public cSmartCardSlotEmuGeneric {
+protected:
+  virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+  virtual void EmuPushAtr(void);
+public:
+  cSmartCardSlotEmuSeca(void);
+  };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotEmuSeca> __scs_emuseca("emuseca");
+
+cSmartCardSlotEmuSeca::cSmartCardSlotEmuSeca(void)
+{
+  strcpy(devName,"emuseca");
+}
+
+int cSmartCardSlotEmuSeca::DeviceWrite(const unsigned char *mem, int len, int delay)
 {
-  PRINTF(L_CORE_SERIAL,"serial: write len=%d delay=%d",len,delay);
+  PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
   Flush();
   cCondWait::SleepMs(300);
   PUSH(mem,len); // echo back
-#if defined(EMU_SECA)
+  //---
   if(cmdStart && len==CMD_LEN) { // new INS
     PUSHB(mem[INS_IDX]); // ACK byte
     cmdStart=false;
@@ -418,7 +1100,41 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
       cmdStart=true;
       }
     }
-#elif defined(EMU_CRYPTO)
+  //---
+  return len;
+}
+
+void cSmartCardSlotEmuSeca::EmuPushAtr(void)
+{
+  static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00,
+                                       0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 };
+  PUSH(atr,sizeof(atr));
+}
+
+// -- cSmartCardSlotEmuCrypto --------------------------------------------------
+
+class cSmartCardSlotEmuCrypto : public cSmartCardSlotEmuGeneric {
+protected:
+  virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+  virtual void EmuPushAtr(void);
+public:
+  cSmartCardSlotEmuCrypto(void);
+  };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotEmuCrypto> __scs_emucrypto("emucrypto");
+
+cSmartCardSlotEmuCrypto::cSmartCardSlotEmuCrypto(void)
+{
+  strcpy(devName,"emucrypto");
+}
+
+int cSmartCardSlotEmuCrypto::DeviceWrite(const unsigned char *mem, int len, int delay)
+{
+  PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
+  Flush();
+  cCondWait::SleepMs(300);
+  PUSH(mem,len); // echo back
+  //---
   if(cmdStart && len==CMD_LEN) { // new INS
     cmdStart=false;
     dataLen=mem[LEN_IDX];
@@ -429,7 +1145,7 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
     switch(mem[0]*256+mem[1]) {
       case 0xa4a4:
         switch(mem[5]*256+mem[6]) {
-          case 0x2f01: 
+          case 0x2f01:
           case 0x0f00:
           case 0x0f20:
           //case 0x0f40:
@@ -500,30 +1216,20 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
                 0x92,0x20,0x00 // ...
                 };
               memcpy(data,resp,sizeof(resp));
-              }    
+              }
             break;
           case 0x80:
             dataLen=0x07;
-            data[0]=0x80;
-            data[1]=0x05;
-            data[2]=0x5c;
-            data[3]=0x0c;
-            data[4]=0x00;
-            data[5]=0xec;
-            data[6]=0x0a;
+            data[0]=0x80; data[1]=0x05; data[2]=0x5c; data[3]=0x0c;
+            data[4]=0x00; data[5]=0xec; data[6]=0x0a;
             break;
           case 0xD1:
             dataLen=0x04;
-            data[0]=0xd1;
-            data[1]=0x02;
-            data[2]=0x0d;
-            data[3]=0x22;
+            data[0]=0xd1; data[1]=0x02; data[2]=0x0d; data[3]=0x22;
             break;
           case 0x9F:
             dataLen=0x03;
-            data[0]=0x9f;
-            data[1]=0x01;
-            data[2]=0x88;
+            data[0]=0x9f; data[1]=0x01; data[2]=0x88;
             break;
           case 0x9E:
             {
@@ -551,10 +1257,7 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
         if(mem[2]==0) {
           dataLen=0x0C;
           memset(data,0,0x0c);
-          data[0]=0xDF;
-          data[1]=0x0A;
-          data[4]=0xDF;
-          data[5]=0x88;
+          data[0]=0xDF; data[1]=0x0A; data[4]=0xDF; data[5]=0x88;
           }
         else {
           dataLen=0;
@@ -567,20 +1270,13 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
       case 0xa4c0:
         readcmd=true;
         if(mem[4]==0x1c) {
-          data[0]=0xdb;
-          data[1]=0x10;
+          data[0]=0xdb; data[1]=0x10;
           memset(&data[2],0x45,16);
-          data[18]=0xdf;
-          data[19]=0x08;
-          data[20]=0x50;
-          data[23]=0x80;
+          data[18]=0xdf; data[19]=0x08; data[20]=0x50; data[23]=0x80;
           }
         else if(mem[4]==0x11) {
           memset(data,0,0x11);
-          data[0]=0xdf;
-          data[1]=0x0f;
-          data[6]=0x3f;
-          data[7]=0x6a;
+          data[0]=0xdf; data[1]=0x0f; data[6]=0x3f; data[7]=0x6a;
           }
         else if(mem[4]==0x42) {
           static const unsigned char resp[0x42] = {
@@ -610,54 +1306,109 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
       cmdStart=true;
       }
     }
-#elif defined(EMU_IRD)
+  //---
+  return len;
+}
+
+void cSmartCardSlotEmuCrypto::EmuPushAtr(void)
+{
+  static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00,
+                                       0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 };
+  PUSH(atr,sizeof(atr));
+}
+
+// -- cSmartCardSlotEmuIrdeto --------------------------------------------------
+
+class cSmartCardSlotEmuIrdeto : public cSmartCardSlotEmuGeneric {
+private:
+  bool acs384;
+protected:
+  virtual bool DeviceOpen(const char *cfg);
+  virtual int DeviceWrite(const unsigned char *mem, int len, int delay=0);
+  virtual void EmuPushAtr(void);
+public:
+  cSmartCardSlotEmuIrdeto(void);
+  };
+
+static cSmartCardSlotLinkReg<cSmartCardSlotEmuIrdeto> __scs_emuirdeto("emuirdeto");
+
+cSmartCardSlotEmuIrdeto::cSmartCardSlotEmuIrdeto(void)
+{
+  strcpy(devName,"emuirdeto");
+  acs384=false;
+}
+
+bool cSmartCardSlotEmuIrdeto::DeviceOpen(const char *cfg)
+{
+  char acs[32];
+  if(sscanf(cfg,"%31[^:]",acs)>=0) {
+    if(!strcasecmp(acs,"acs384")) acs384=true;
+    else if(!strcasecmp(acs,"acs383")) acs384=false;
+    else {
+      PRINTF(L_GEN_ERROR,"unknown ACS type");
+      return false;
+      }
+    return cSmartCardSlotEmuGeneric::DeviceOpen(0);
+    }
+  else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",devName);
+  return false;
+}
+
+int cSmartCardSlotEmuIrdeto::DeviceWrite(const unsigned char *mem, int len, int delay)
+{
+  PRINTF(L_CORE_SERIAL,"%s: write len=%d delay=%d",devName,len,delay);
+  Flush();
+  cCondWait::SleepMs(300);
+  PUSH(mem,len); // echo back
+  //---
   static const struct Resp {
     unsigned int cmd;
+    int acs;
     unsigned char data[MAX_LEN];
     } resp[] = {
-#ifdef EMU_IRD_384
-  { 0x01020203,
+  { 0x01020203,0x384,
     {0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x84,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} },
-  { 0x01020E02,
+  { 0x01020E02,0x384,
     {0x01,0x02,0x00,0x00,0x0e,0x02,0x00,0x40,0xa9,0x6d,0x73,0x97,0x9e,0xfc,0x9b,0x8e,0x5b,0x8c,0xfa,0xb2,0x0c,0xb2,0x57,0x0f,0xb2,0xf7,0x29,0x4e,0xa2,0xcb,0xbd,0x5b,0x52,0x74,0xb1,0x2a,0xb7,0xc5,0xd9,0x62,0x6d,0x37,0x6d,0x9d,0xa3,0xe9,0x61,0xbb,0x1b,0x2b,0x56,0xb7,0x86,0x0c,0xe6,0xb1,0x07,0x6f,0xe0,0xf8,0x8a,0xd3,0x05,0x83,0xf6,0x53,0x0e,0xd2,0x72,0xd5,0xc1,0x50} },
-  { 0x01020E03,
+  { 0x01020E03,0x384,
     {0x01,0x02,0x00,0x00,0x0e,0x03,0x00,0x40,0xb6,0xde,0xa8,0xce,0x86,0x1c,0x42,0x72,0xa8,0x16,0x4b,0xf9,0xce,0x33,0xb5,0x43,0xd0,0x50,0xe6,0xa7,0xf1,0xcb,0x55,0x25,0x97,0x13,0xee,0x62,0x98,0xe7,0x17,0x50,0xeb,0x3b,0x59,0x10,0x0a,0xb6,0x2e,0x93,0x61,0x71,0x3c,0xe6,0xe2,0x2c,0x1e,0x7d,0xbd,0x6a,0x49,0xbb,0x04,0x5b,0xdf,0x2f,0xb7,0xa7,0x93,0xe0,0x3d,0x40,0x4e,0xd1} },
-#else
-  { 0x01020203,
+  //
+  { 0x01020203,0x383,
     {0x01,0x02,0x00,0x00,0x02,0x00,0x00,0x10,0x03,0x83,0x00,0x00,0x00,0x17,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x47,0x45,0x52} },
-  { 0x01020E02,
+  { 0x01020E02,0x383,
     {0x01,0x02,0x00,0x00,0x0E,0x02,0x00,0x40,0x65,0xEF,0xD0,0xA7,0xF3,0x80,0x48,0x0E,0xC1,0x4B,0x41,0x6C,0xDB,0x68,0x47,0xE4,0x23,0xAD,0x96,0x12,0x07,0x58,0x58,0x29,0xE9,0x14,0x27,0x7F,0x7D,0xF8,0xC2,0x65,0x76,0x4D,0x75,0x04,0x7C,0x9B,0xAA,0x99,0x58,0xEA,0xE2,0x43,0xB5,0x03,0x05,0xD6,0x62,0x99,0xF5,0x18,0x16,0x4E,0xCF,0x49,0x11,0xBD,0xF3,0xEE,0xC3,0xCD,0x90,0x3B} },
-  { 0x01020E03,
+  { 0x01020E03,0x383,
     {0x01,0x02,0x00,0x00,0x0E,0x03,0x00,0x40,0x9B,0x06,0xB5,0x0A,0x98,0xC6,0x2E,0x1D,0x71,0xA1,0xE8,0x84,0xAE,0x98,0x57,0xE9,0xE6,0xC2,0x97,0x46,0x25,0x7A,0x2B,0xA1,0xD5,0x33,0x18,0xDE,0x16,0xC1,0xAB,0x22,0x2C,0xC2,0x11,0x24,0x81,0x11,0xA8,0x39,0xE3,0xB1,0xDB,0x33,0x1A,0x93,0x31,0xB0,0x61,0xD8,0xDE,0x92,0x1F,0x29,0x20,0xD0,0x9E,0x0F,0x6A,0xF0,0x7C,0xBA,0xCD,0xCC} },
-#endif
-  { 0x01020003,
+  //
+  { 0x01020003,0x0,
     {0x01,0x02,0x00,0x00,0x00,0x03,0x00,0x14,0x37,0x30,0x31,0x32,0x30,0x36,0x39,0x33,0x34,0x37,0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} },
-  { 0x01020103,
+  { 0x01020103,0x0,
     {0x01,0x02,0x00,0x00,0x01,0x00,0x00,0x10,0x00,0x17,0x00,0x00,0x01,0x00,0x17,0x00,0x00,0x01,0x04,0x00,0xF3,0x86,0x01,0x1A} },
-  { 0x01021100,
+  { 0x01021100,0x0,
     {0x01,0x02,0x58,0x00,0x11,0x00,0x00,0x00} },
-  { 0x01020903,
+  { 0x01020903,0x0,
     {0x01,0x02,0x55,0x00,0x09,0x03,0x00,0x00} },
-  { 0x01020303,
+  { 0x01020303,0x0,
     {0x01,0x02,0x00,0x00,0x03,0x03,0x02,0x18,0x0F,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x31,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} },
-  { 0x01020400,
+  { 0x01020400,0x0,
     {0x01,0x02,0x54,0x00,0x04,0x00,0x00,0x00} },
-  { 0x01050000,
+  { 0x01050000,0x0,
     {0x01,0x05,0x9D,0x00,0x38,0x00,0x02,0x16,0x00,0x01,0x00,0x13,0xFF,0xFF,0x22,0x88,0xBF,0x02,0x70,0xFA,0x5F,0x80,0xFD,0x1E,0xD4,0xD6,0xF0,0xF1,0x81,0xB3} },
-  { 0x01010000,
+  { 0x01010000,0x0,
     {0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0xFF} },
-  { 0x00000000, // don't delete this one
+  { 0x00000000,0x0, // don't delete this one
     {} }
   };
   const unsigned int cmd=(mem[0]<<24) + (mem[1]<<16) + (mem[2]<<8) + mem[3];
   const struct Resp *r=&resp[0];
+  int acs=acs384 ? 0x384:0x383;
   while(1) {
     if(!r->cmd) {
       static const unsigned char fail[] = { 0x01,0x99,0x6f };
       PUSH(fail,sizeof(fail));
       break;
       }
-    if(cmd==r->cmd) {
+    if(cmd==r->cmd && (!r->acs || r->acs==acs)) {
       const int len=r->data[7]+9-1;
       int cs=0x3f;
       for(int i=0 ; i<len ; i++) cs ^= r->data[i];
@@ -667,50 +1418,21 @@ int cSerial::Write(const unsigned char *mem, int len, int delay)
       }
     r++;
     }
-#else
-#error No serial emulation mode selected
-#endif
+  //---
   return len;
 }
 
-void cSerial::ToggleRTS(void)
-{
-  rts=!rts;
-  if(!rts) { 
-#if defined(EMU_SECA)
-    static const unsigned char atr[] = { 0x3b,0x77,0x12,0x00,0x00,
-                                         0x60,0x60,0x03,0x0E,0x6C,0xB6,0xD6 };
-#elif defined(EMU_IRD)
-    static const unsigned char atr[] = { 0x3B,0x9F,0x21,0x0E,
-#ifdef EMU_IRD_384
-                                         0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d };
-#else
-                                         0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 };
-#endif
-#elif defined(EMU_CRYPTO)
-    static const unsigned char atr[] = { 0x3B,0x78,0x12,0x00,0x00,
-                                         0x65,0xC4,0x05,0x05,0x8F,0xF1,0x90,0x00 };
-#else
-#error No serial emulation mode selected
-#endif
-    PUSH(atr,sizeof(atr));
-    PRINTF(L_CORE_SERIAL,"serial: toggle RTS, now off");
-    }
-  else { PRINTF(L_CORE_SERIAL,"serial: toggle RTS, now on"); }
-}
-
-bool cSerial::CheckCAR(void)
+void cSmartCardSlotEmuIrdeto::EmuPushAtr(void)
 {
-#if 0
-  if(time(0)>=remTime+30) {
-    dsr=!dsr;
-    remTime=time(0);
-    }
-#endif
-  return dsr;
+  static const unsigned char atr384[] = { 0x3B,0x9F,0x21,0x0E,
+                                          0x49,0x52,0x44,0x45,0x54,0x4f,0x20,0x41,0x43,0x53,0x03,0x84,0x55,0xff,0x80,0x6d };
+  static const unsigned char atr383[] = { 0x3B,0x9F,0x21,0x0E,
+                                          0x49,0x52,0x44,0x45,0x54,0x4F,0x20,0x41,0x43,0x53,0x03,0x83,0x95,0x00,0x80,0x55 };
+  if(acs384) PUSH(atr384,sizeof(atr384))
+  else       PUSH(atr383,sizeof(atr383))
 }
 
-#endif //SER_EMU
+#endif // CARD_EMU
 
 // -- cInfoStr -----------------------------------------------------------------
 
@@ -749,384 +1471,123 @@ void cInfoStr::Finish()
 
 // -- cSmartCardData -----------------------------------------------------------
 
-cSmartCardData::cSmartCardData(int Ident)
-{
-  ident=Ident;
-}
-
-// -- cSmartCardDatas ----------------------------------------------------------
-
-cSmartCardDatas carddatas;
-
-cSmartCardDatas::cSmartCardDatas(void)
-:cStructList<cSmartCardData>("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE)
-{}
-
-cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param)
-{
-  ListLock(false);
-  cSmartCardData *cd;
-  for(cd=First(); cd; cd=Next(cd))
-    if(cd->Ident()==param->Ident() && cd->Matches(param)) break;
-  ListUnlock();
-  return cd;
-}
-
-cStructItem *cSmartCardDatas::ParseLine(char *line)
-{
-  char *r=index(line,':');
-  if(r)
-    for(cSmartCardLink *scl=cSmartCards::first; scl; scl=scl->next)
-      if(!strncasecmp(scl->name,line,r-line)) {
-        cSmartCardData *scd=scl->CreateData();
-        if(scd && scd->Parse(r+1)) return scd;
-        delete scd;
-        break;
-        }
-  return 0;
-}
-
-// -- cSmartCardSlot -----------------------------------------------------------
-
-cSmartCardSlot::cSmartCardSlot(int num)
-{
-  Serial=0; Card=0;
-  CardId=0; UseCount=0; Dead=false;
-  SlotNum=num;
-  Clock=ISO_FREQ;
-}
-
-cSmartCardSlot::~cSmartCardSlot()
-{
-  delete Card;
-  delete Serial;
-}
-
-// -- cSmartCard ---------------------------------------------------------------
-
-static const int Ftable[16] = {
-  372,372,558,744,1116,1488,1860,0,0,512,768,1024,1536,2048,0,0
-  };
-
-static const float Dtable[16] = {
-  0.0,1.0,2.0,4.0,8.0,16.0,0.0,0.0,
-  0.0,0.0,0.5,0.25,0.125,0.0625,0.03125,0.015625
-  };
-  
-cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg)
-{
-  msg=Msg;
-  ser=0; atr=0; idStr[0]=0; cardUp=false; needsReset=true;
-  NewCardConfig(Cfg);
-}
-
-void cSmartCard::NewCardConfig(const struct CardConfig *Cfg)
-{
-  cfg=Cfg;
-}
-
-bool cSmartCard::GetCardIdStr(char *str, int len)
-{
-  strn0cpy(str,idStr,len);
-  return (str[0]!=0);
-}
-
-bool cSmartCard::GetCardInfoStr(char *str, int len)
-{
-  return infoStr.Get(str,len);
-}
-
-bool cSmartCard::Setup(cSerial *Ser, const struct Atr *Atr, int Id)
-{
-  ser=Ser; atr=Atr; id=Id;
-  if(cfg->SerMode==(ser->CurrentMode()&SM_MASK) && Init()) {
-    cardUp=true; needsReset=false;
-    return true;
-    }
-  return false;
-}
-
-#define NEED(x) { \
-                if(len+(x)>Atr->atrLen) { \
-                    LBPUT("SHORT ATR"); \
-                    return false; \
-                    } \
-                }
-
-bool cSmartCard::ParseAtr(struct Atr *Atr, int id, int clock)
-{
-  // default values
-  Atr->histLen=0; Atr->T=0; Atr->F=372; Atr->D=1.0; Atr->N=0; Atr->WI=10;
-  Atr->BWI=4; Atr->CWI=0; Atr->Tspec=-1;
-
-  const unsigned char *atr=Atr->atr;
-  if(atr[0]==0x03) {
-    PRINTF(L_CORE_SC,"%d: indirect convention detected",id);
-    cSmartCard::Invert(Atr->atr,Atr->atrLen);
-    Atr->convention=SM_INDIRECT;
-    }
-  else if(atr[0]==0x3B) {
-    PRINTF(L_CORE_SC,"%d: direct convention detected",id);
-    Atr->convention=SM_DIRECT;
-    }
-  else {
-    PRINTF(L_CORE_SC,"%d: byte mode not supported 0x%02x",id,atr[0]);
-    return false;
-    }
-
-  // TS TO
-  Atr->histLen=atr[1]&0x0F;
-  int Y=atr[1]&0xF0, i=1, len=2;
-  LBSTARTF(L_CORE_SC);
-  LBPUT("%d: atr decoding TS=%02x hist=%d Y%d=%02x ",id,atr[0],Atr->histLen,i,Y);
-  do {
-    if(Y&0x10) { // TAi
-      NEED(1);
-      LBPUT("TA%d=%02x ",i,atr[len]);
-      if(i==1) {
-        Atr->TA1=atr[len];
-        Atr->F=Ftable[(atr[len]>>4)&0x0F];
-        Atr->D=Dtable[ atr[len]    &0x0F];
-        LBPUT("F=%d D=%f ",Atr->F,Atr->D);
-        }
-      else if(i==2) {
-        Atr->Tspec=atr[len]&0x0F;
-        LBPUT("Tspec=%d ",Atr->Tspec);
-        }
-      else if(i==3) {
-        LBPUT("IFSC=%d ",atr[len]);
-        }
-      len++;
-      }
-    if(Y&0x20) { // TBi
-      NEED(1);
-      LBPUT("TB%d=%02x ",i,atr[len]);
-      if(i==3) {
-        Atr->BWI=(atr[len]>>4)&0x0F;
-        Atr->CWI=atr[len]&0x0F;
-        LBPUT("BWI=%d CWI=%d ",Atr->BWI,Atr->CWI);
-        }
-      len++;
-      }
-    if(Y&0x40) { // TCi
-      NEED(1);
-      LBPUT("TC%d=%02x ",i,atr[len]);
-      if(i==1) {
-        Atr->N=atr[len];
-        LBPUT("N=%d ",Atr->N);
-        }
-      else if(i==2) {
-        Atr->WI=atr[len];
-        LBPUT("WI=%d ",Atr->WI);
-        }
-      else if(i==3) {
-        LBPUT("CHK=%s ",atr[len]&1 ? "CRC16":"LRC");
-        }
-      len++;
-      }
-    if(Y&0x80) { // TDi
-      NEED(1);
-      LBPUT("TD%d=%02x ",i,atr[len]);
-      if(i==1) {
-        Atr->T=atr[len]&0x0F;
-        LBPUT("T=%d ",Atr->T);
-        }
-      else {
-        LBPUT("Tn=%d ",atr[len]&0x0F);
-        }
-      Y=atr[len]&0xF0;
-      len++;
-      }
-    else Y=0;
-    i++;
-    LBPUT("Y%d=%02x ",i,Y);
-    } while(Y);
-  NEED(Atr->histLen);
-  LBEND();
-
-  LBSTART(L_CORE_SC);
-  LBPUT("%d: historical:",id);
-  for(int i=0 ; i<Atr->histLen ; i++) LBPUT(" %02x",atr[len+i]);
-  LBFLUSH();
-  LBPUT("%d: historical: '",id);
-  for(int i=0 ; i<Atr->histLen ; i++) LBPUT("%c",isprint(atr[len+i]) ? atr[len+i] : '.');
-  LBEND();
+cSmartCardData::cSmartCardData(int Ident)
+{
+  ident=Ident;
+}
 
-  memcpy(Atr->hist,&atr[len],Atr->histLen);
-  len+=Atr->histLen;
+// -- cSmartCardDatas ----------------------------------------------------------
 
-  // TCK
-  if(Atr->T!=0 && len+1<=Atr->atrLen) {
-    len++;
-    unsigned char cs=XorSum(atr+1,len-1);
-    // according to the ISO the initial TS byte isn't checksumed, but
-    // some cards do so. In this case the checksum is equal TS.
-    if(cs==0) PRINTF(L_CORE_SC,"%d: atr checksum ok",id);
-    else if(cs==atr[0]) PRINTF(L_CORE_SC,"iso: %d: atr checksum is TS (not ISO compliant)",id);
-    else {
-      PRINTF(L_CORE_SC,"%d: atr checksum FAILED (cs:%02x)",id,cs);
-      return false;
-      }
-    }
-  else PRINTF(L_CORE_SC,"%d: atr checksum not given/not required",id);
+class cSmartCardDatas : public cStructList<cSmartCardData> {
+protected:
+  virtual cStructItem *ParseLine(char *line);
+public:
+  cSmartCardDatas(void);
+  cSmartCardData *Find(cSmartCardData *param);
+  };
 
-  if(Atr->atrLen>len) PRINTF(L_CORE_SC,"%d: long atr read=%d len=%d",id,Atr->atrLen,len);
-  Atr->wwt=960*Atr->WI*Atr->F/(clock/1000);
-  Atr->bwt=(int)(960*(float)(1<<Atr->BWI)*372/(clock/1000));
-  PRINTF(L_CORE_SC,"%d: indicated wwt(T0)=%d ms, bwt(T1)=%d ms (at %.4f MHz)",id,Atr->wwt,Atr->bwt,(float)clock/1000000);
-  return true;
+static cSmartCardDatas carddatas;
+
+cSmartCardDatas::cSmartCardDatas(void)
+:cStructList<cSmartCardData>("smartcard data","smartcard.conf",SL_MISSINGOK|SL_WATCH|SL_VERBOSE)
+{}
+
+cSmartCardData *cSmartCardDatas::Find(cSmartCardData *param)
+{
+  ListLock(false);
+  cSmartCardData *cd;
+  for(cd=First(); cd; cd=Next(cd))
+    if(cd->Ident()==param->Ident() && cd->Matches(param)) break;
+  ListUnlock();
+  return cd;
 }
 
-void cSmartCard::Invert(unsigned char *data, int n)
+cStructItem *cSmartCardDatas::ParseLine(char *line)
 {
-  static const unsigned char swaptab[] =  { 15,7,11,3,13,5,9,1,14,6,10,2,12,4,8,0 };
-  for(int i=n-1; i>=0; i--)
-    data[i]=(swaptab[data[i]&0x0f]<<4) | swaptab[data[i]>>4];
+  char *r=index(line,':');
+  if(r)
+    for(cSmartCardLink *scl=smartcards.First(); scl; scl=smartcards.Next(scl))
+      if(!strncasecmp(scl->Name(),line,r-line)) {
+        cSmartCardData *scd=scl->CreateData();
+        if(scd && scd->Parse(r+1)) return scd;
+        delete scd;
+        break;
+        }
+  return 0;
 }
 
-int cSmartCard::SerRead(unsigned char *data, int len, int to)
+// -- cSmartCard ---------------------------------------------------------------
+
+cSmartCard::cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg)
 {
-  if(atr->T==1 || atr->T==14) {
-    int r=Read(data,len,to);
-    if(r<0) Test(false);
-    return r;
-    }
-  else {
-    PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",id,atr->T);
-    return -1;
-    }
+  msg=Msg;
+  slot=0; atr=0; idStr[0]=0; cardUp=false;
+  NewCardConfig(Cfg);
 }
 
-int cSmartCard::SerWrite(const unsigned char *data, int len)
+void cSmartCard::NewCardConfig(const struct CardConfig *Cfg)
 {
-  if(atr->T==1 || atr->T==14) {
-    int r=Write(data,len);
-    if(r<0) Test(false);
-    return r;
-    }
-  else {
-    PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",id,atr->T);
-    return -1;
-    }
+  cfg=Cfg;
 }
 
-int cSmartCard::Read(unsigned char *data, int len, int to)
+bool cSmartCard::GetCardIdStr(char *str, int len)
 {
-  int r=ser->Read(data,len,cfg->serTO,to);
-  if(atr->convention==SM_INDIRECT && r>0) Invert(data,r);
-  return r;
+  strn0cpy(str,idStr,len);
+  return (str[0]!=0);
+}
+
+bool cSmartCard::GetCardInfoStr(char *str, int len)
+{
+  return infoStr.Get(str,len);
 }
 
-int cSmartCard::Write(const unsigned char *data, int len)
+bool cSmartCard::Setup(cSmartCardSlot *Slot, int sermode, const struct Atr *Atr)
 {
-  unsigned char *tmp=AUTOMEM(len);
-  if(atr->convention==SM_INDIRECT) {
-    memcpy(tmp,data,len);
-    Invert(tmp,len);
-    data=tmp;
-    }
-  int r=ser->Write(data,len,cfg->serDL);
-  if(r>0) {
-    unsigned char *buff=AUTOMEM(r);
-    int rr=ser->Read(buff,r,cfg->serTO);
-    if(rr<0) r=rr;
-    }
-  return r;
+  slot=Slot; atr=Atr; slotnum=slot->SlotNum();
+  cardUp=false;
+  if(cfg->SerMode==sermode && Init()) cardUp=true;
+  return cardUp;
 }
 
-int cSmartCard::Procedure(unsigned char ins, int restLen)
+int cSmartCard::SerRead(unsigned char *data, int len, int to)
 {
-  int r;
-  unsigned char buff;
-  LBSTARTF(L_CORE_SC);
-  LBPUT("%d: <- PROC: ",id);
-  do {
-    do {
-      if(Read(&buff,1,cfg->workTO)<=0) return -1;
-      LBPUT("%02x ",buff);
-      } while(buff==0x60);
+  if(atr->T==1 || atr->T==14) return slot->RawRead(data,len,to);
+  PRINTF(L_CORE_SC,"%d: SerRead() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T);
+  return -1;
+}
 
-    if((buff&0xF0)==0x60 || (buff&0xF0)==0x90) { // SW1/SW2
-      sb[0]=buff;
-      if(Read(&buff,1)<=0) return -1;
-      LBPUT("%02x",buff);
-      sb[1]=buff;
-      return 0;
-      }
-    else {
-      if((buff&0xFE)==(ins&0xFE)) r=restLen;
-      else if((~buff&0xFE)==(ins&0xFE)) r=1;
-      else {
-        LBPUT("cannot handle procedure %02x (ins=%02x)",buff,ins);
-        return -1;
-        }
-      if(r>restLen) {
-        LBPUT("data overrun r=%d restLen=%d",r,restLen);
-        return -1;
-        }
-      }
-    } while(r==0);
-  LBEND();
-  return r;
+int cSmartCard::SerWrite(const unsigned char *data, int len)
+{
+  if(atr->T==1 || atr->T==14) return slot->RawWrite(data,len);
+  PRINTF(L_CORE_SC,"%d: SerWrite() not allowed for ISO compliant cards (T=%d)",slotnum,atr->T);
+  return -1;
 }
 
 bool cSmartCard::IsoRead(const unsigned char *cmd, unsigned char *data)
 {
-  if(atr->T==0) { // only for ISO complaint cards
-    LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",id);
-    if(Write(cmd,CMD_LEN)<0) return Test(false);
-    int tr=cmd[LEN_IDX] ? cmd[LEN_IDX] : 256;
-    int len=0;
-    while(1) {
-      int r=Procedure(cmd[INS_IDX],tr-len);
-      if(r<=0) return Test(r==0);
-      if(Read(data+len,r)<0) return Test(false);
-      LDUMP(L_CORE_SC,data+len,r,"%d: <- DATA:",id);
-      len+=r;
-      }
-    }
-  else PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",id,atr->T);
+  if(atr->T==0) return slot->IsoRead(cmd,data);
+  PRINTF(L_CORE_SC,"%d: can't IsoRead() from incompatible card (T=%d)",slotnum,atr->T);
   return false;
 }
 
 bool cSmartCard::IsoWrite(const unsigned char *cmd, const unsigned char *data)
 {
-  if(atr->T==0) { // only for ISO complaint cards
-    LDUMP(L_CORE_SC,cmd,CMD_LEN,"%d: -> INS:",id);
-    if(Write(cmd,CMD_LEN)<0) return Test(false);
-    int len=0;
-    while(1) {
-      int r=Procedure(cmd[INS_IDX],cmd[LEN_IDX]-len);
-      if(r<=0) return Test(r==0);
-      if(Write(data+len,r)<0) return Test(false);
-      LDUMP(L_CORE_SC,data+len,r,"%d: -> DATA:",id);
-      len+=r;
-      }
-    }
-  else PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",id,atr->T);
+  if(atr->T==0) return slot->IsoWrite(cmd,data);
+  PRINTF(L_CORE_SC,"%d: can't IsoWrite() to incompatible card (T=%d)",slotnum,atr->T);
   return false;
 }
 
-bool cSmartCard::Test(bool res)
-{
- if(!res) {
-   TriggerReset();
-   PRINTF(L_CORE_SC,"%d: reset triggered",id);
-   }
- return res;
-}
-
 bool cSmartCard::Status(void)
 {
   const struct StatusMsg *m=msg;
   while(m->sb[0]!=0xFF) {
     if(sb[0]==m->sb[0] && (m->sb[1]==0xFF || sb[1]==m->sb[1])) {
-      if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",id,m->message,sb[0],sb[1]);
+      if(!m->retval) PRINTF(L_CORE_SC,"%d: %s (status: %02x %02x)",slotnum,m->message,sb[0],sb[1]);
       return m->retval;
       }
     m++;
     }
-  PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",id,sb[0],sb[1]);
+  PRINTF(L_CORE_SC,"%d: unknown (status: %02x %02x)",slotnum,sb[0],sb[1]);
   return false;
 }
 
@@ -1154,15 +1615,6 @@ cSmartCardLink *cSmartCards::first=0;
 
 cSmartCards smartcards;
 
-static const char *serModes[] = { 0,"8e2","8o2","8n2" };
-
-cSmartCards::cSmartCards(void)
-:cThread("SmartcardWatcher")
-,cStructListPlain<cSmartCardSlot>("cardslot config","cardslot.conf",SL_MISSINGOK|SL_VERBOSE|SL_NOPURGE)
-{
-  firstRun=true;
-}
-
 void cSmartCards::Register(cSmartCardLink *scl)
 {
   PRINTF(L_CORE_DYN,"registering %s smartcard (id %x)",scl->name,scl->id);
@@ -1170,329 +1622,71 @@ void cSmartCards::Register(cSmartCardLink *scl)
   first=scl;
 }
 
-void cSmartCards::LaunchWatcher(void)
-{
-  firstRun=true;
-  if(Count()>0) Start();
-  else {
-    firstRun=false;
-    PRINTF(L_GEN_WARN,"no smartcard slot defined!");
-    }
-}
-
 void cSmartCards::Shutdown(void)
 {
-  PreLoad();
+  carddatas.SafeClear();
+  cardslots.SafeClear();
 }
 
-void cSmartCards::PreLoad(void)
+void cSmartCards::Disable(void)
 {
-  Cancel(3);
-  mutex.Lock();
-  Clear(); Modified(false);
-  mutex.Unlock();
+  carddatas.Disable();
+  cardslots.Disable();
 }
 
-bool cSmartCards::ParseLinePlain(const char *line)
+cSmartCardData *cSmartCards::FindCardData(cSmartCardData *param)
 {
-  char type[32];
-  int num;
-  if(sscanf(line,"%31[^:]:%n",type,&num)==1) {
-    if(!strcasecmp(type,"serial")) {
-      int invCD=0, invRST=0, clock=0;
-      char devName[64];
-      if(sscanf(&line[num],"%63[^:]:%d:%d:%d",devName,&invCD,&invRST,&clock)>=3) {
-        cSmartCardSlot *slot=new cSmartCardSlot(Count());
-        if(slot) {
-          cSerial *ser=new cSerial(devName,invCD,invRST);
-          if(ser && ser->Open()) {
-            slot->Serial=ser;
-            if(clock>0) slot->Clock=clock;
-            Add(slot);
-            PRINTF(L_CORE_LOAD,"smartcards: added serial port %s as port %d (%s CD, %s RESET, CLOCK %d)",
-                      devName,slot->SlotNum,invCD?"inverse":"normal",invRST?"inverse":"normal",slot->Clock);
-            return true;
-            }
-          else PRINTF(L_GEN_ERROR,"failed to open serial port %s",devName);
-          delete ser;
-          delete slot;
-          }
-        else PRINTF(L_GEN_ERROR,"failed to create cardslot");
-        }
-      else PRINTF(L_GEN_ERROR,"bad parameter for cardslot type '%s'",type);
-      }
-    else PRINTF(L_GEN_ERROR,"unknown cardslot type '%s'",type);
-    }
-  return false;
+  return carddatas.Find(param);
 }
 
-
 bool cSmartCards::HaveCard(int id)
 {
-  cMutexLock lock(&mutex);
-  while(Running() && firstRun) cond.Wait(mutex);
-  for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
-    if(slot->CardId==id) return true;
-  return false;
+  bool res=false;
+  for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
+    if(slot->HaveCard(id)) { res=true; break; }
+  cardslots.Release();
+  return res;
 }
 
 cSmartCard *cSmartCards::LockCard(int id)
 {
-  mutex.Lock();
-  while(Running() && firstRun) cond.Wait(mutex);
-  for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) {
-    if(slot->CardId==id) {
-      slot->UseCount++;
-      mutex.Unlock();
-      cSmartCard *sc=slot->Card;
-      sc->Lock();
-      if(CardInserted(slot->Serial) && sc->CardUp() && !sc->NeedsReset())
-        return sc;
-      // if failed, unlock the card and decrement UseCount
-      sc->Unlock();
-      mutex.Lock();
-      slot->UseCount--;
-      cond.Broadcast();
-      break;
-      }
-    }
-  mutex.Unlock();
-  return 0;
+  cSmartCard *sc=0;
+  for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
+    if((sc=slot->LockCard(id))) break;
+  cardslots.Release();
+  return sc;
 }
 
 void cSmartCards::ReleaseCard(cSmartCard *sc)
 {
-  sc->Unlock();
-  mutex.Lock();
-  for(cSmartCardSlot *slot=First(); slot; slot=Next(slot)) {
-    if(slot->Card==sc) {
-      slot->UseCount--;
-      cond.Broadcast();
-      mutex.Unlock();
-      return;
-      }
-    }
-  mutex.Unlock();
-  PRINTF(L_GEN_DEBUG,"internal: can't find port in cSmartCards::ReleaseCard()");
-}
-
-bool cSmartCards::CardInserted(cSerial *ser)
-{
-  return ser->CheckCAR();
-}
-
-bool cSmartCards::CardReset(cSmartCardSlot *port)
-{
-  if(Reset(port)<2 || !cSmartCard::ParseAtr(&port->Atr,port->SlotNum,port->Clock))
-    return false;
-  if(!DoPTS(port)) {
-    // reset card again and continue without PTS
-    if(Reset(port)<2 || !cSmartCard::ParseAtr(&port->Atr,port->SlotNum,port->Clock))
-      return false;
-    }
-  return true;
-}
-
-int cSmartCards::Reset(cSmartCardSlot *port)
-{
-  cSerial *ser=port->Serial;
-  PRINTF(L_CORE_SC,"%d: reseting card (sermode %s)",port->SlotNum,serModes[ser->CurrentMode()]);
-  ser->ToggleRTS();
-  cCondWait::SleepMs(100);
-  ser->ToggleRTS();
-  int r=ser->Read(port->Atr.atr,-MAX_ATR_LEN,800,2000);
-  port->Atr.atrLen=r;
-  if(r>0) LDUMP(L_CORE_SC,port->Atr.atr,r,"%d: <- ATR len=%d:",port->SlotNum,r);
-  return r;
-}
-
-bool cSmartCards::DoPTS(cSmartCardSlot *port)
-{
-  const struct Atr *atr=&port->Atr;
-  if(atr->F!=372 || atr->D!=1.0) { // PTS required
-    cSerial *ser=port->Serial;
-    const int id=port->SlotNum;
-    int baud=(int)((float)port->Clock*atr->D/atr->F);
-    PRINTF(L_CORE_SC,"%d: PTS cycle: calculated baudrate %d",id,baud);
-
-    if(atr->Tspec<0) {
-      PRINTF(L_CORE_SC,"%d: negotiable mode",id);
-#ifdef NO_PTS_PROTO
-      PRINTF(L_CORE_SC,"%d: PTS disabled at compile time!!!",id);
-      return true;
-#else
-      unsigned char req[4], conf[16];
-      req[0]=0xFF;
-      req[1]=0x10 | atr->T;
-      req[2]=atr->TA1;
-      req[3]=XorSum(req,3);
-      LDUMP(L_CORE_SC,req,4,"%d: PTS request:",id);
-      if(ser->Write(req,4)!=4) {
-        PRINTF(L_CORE_SC,"%d: PTS request, write failed",id);
-        return false;
-        }
-      if(ser->Read(conf,4,100,100)!=4) {
-        PRINTF(L_CORE_SC,"%d: PTS request, echo readback failed",id);
-        return false;
-        }
-      int n=ser->Read(conf,-16,200,1000);
-      if(n>0) LDUMP(L_CORE_SC,conf,n,"%d: PTS confirm:",id);
-      if(n<1 || conf[0]!=0xFF || XorSum(conf,n)!=0) {
-        PRINTF(L_CORE_SC,"%d: PTS confirm, bad format",id);
-        return false;
-        }
-      if(n<4 || conf[1]!=req[1] || conf[2]!=req[2]) {
-        PRINTF(L_CORE_SC,"%d: PTS not confirmed",id);
-        return false;
-        }
-#endif // NO_PTS_PROTO
-      }
-    else
-      PRINTF(L_CORE_SC,"%d: specific mode Tspec=%d",id,atr->Tspec);
-
-    int mode=ser->CurrentMode();
-    if(atr->N==255) mode|=SM_1SB;
-    if(!ser->SetMode(mode,baud)) {
-      PRINTF(L_CORE_SC,"%d: setting baudrate %d failed",id,baud);
-      return false;
-      }
-    }
- return true;
-}
-
-void cSmartCards::SetPort(cSmartCardSlot *port, cSmartCard *sc, int id, bool dead)
-{
-  mutex.Lock();
-  while(port->UseCount) cond.Wait(mutex);
-  delete port->Card;
-  port->Card=sc;
-  port->CardId=id;
-  port->Dead=dead;
-  port->UseCount=0;
-  mutex.Unlock();
-}
-
-void cSmartCards::Action(void)
-{
-  while(Running()) {
-  for(cSmartCardSlot *slot=First(); slot;) {
-      cSerial *ser=slot->Serial;
-      if(ser) {
-        if(slot->Card) {
-          cSmartCard *sc=slot->Card;
-          sc->Lock();
-          if(!CardInserted(ser)) {
-            sc->Unlock(); sc=0;
-            PRINTF(L_CORE_SC,"%d: card removed (UseCount=%d)",slot->SlotNum,slot->UseCount);
-            SetPort(slot,0,0,false);
-            }
-          else if(sc->NeedsReset()) {
-            PRINTF(L_CORE_SC,"%d: card reset requested",slot->SlotNum);
-            if(!ser->SetMode(ser->CurrentMode()&SM_MASK)
-                || !CardReset(slot)
-                || !sc->Setup(ser,&slot->Atr,slot->SlotNum)) {
-              sc->Unlock(); sc=0;
-              PRINTF(L_CORE_SC,"%d: card re-init failed",slot->SlotNum);
-              SetPort(slot,0,0,true);
-              }
-            }
-          if(sc) sc->Unlock();
-          }
-        else if(CardInserted(ser)) {
-          if(!slot->Dead) {
-            PRINTF(L_CORE_SC,"%d: new card inserted",slot->SlotNum);
-            for(int mode=SM_NONE+1 ; mode<SM_MAX ; mode++) {
-              if(ser->SetMode(mode)) {
-                if(CardReset(slot)) {
-                  cSmartCardLink *scl=first;
-                  while(scl) {
-                    PRINTF(L_CORE_SC,"%d: checking for %s card",slot->SlotNum,scl->name);
-                    cSmartCard *sc=scl->Create();
-                    if(sc && sc->Setup(ser,&slot->Atr,slot->SlotNum)) {
-                      SetPort(slot,sc,scl->id,false);
-                      goto next; // ugly, any better solution?
-                      }
-                    delete sc;
-                    scl=scl->next;
-                    }
-                  PRINTF(L_CORE_SC,"%d: no card handler found",slot->SlotNum);
-                  }
-                else PRINTF(L_CORE_SC,"%d: reset/atr error",slot->SlotNum);
-                }
-              else PRINTF(L_CORE_SC,"%d: failed to set serial mode %s",slot->SlotNum,serModes[mode]);
-              }
-            slot->Dead=true;
-            PRINTF(L_CORE_SC,"%d: can't initialise new card, ignoring port until card reinserted",slot->SlotNum);
-            }
-          }
-        else {
-          if(slot->Dead) PRINTF(L_CORE_SC,"%d: card removed, port reactivated",slot->SlotNum);
-          slot->Dead=false;
-          }
-        }
-next: slot=Next(slot);
-      }
-    if(firstRun) {
-      mutex.Lock();
-      cond.Broadcast();
-      firstRun=false;
-      mutex.Unlock();
-      }
-    cCondWait::SleepMs(300);
-    }  
-}
-
-cSmartCardSlot *cSmartCards::GetSlot(int num)
-{
-  for(cSmartCardSlot *slot=First(); slot; slot=Next(slot))
-    if(slot->SlotNum==num) return slot;
-  return 0;
+  for(cSmartCardSlot *slot=cardslots.FirstSlot(); slot; slot=cardslots.Next(slot))
+    slot->ReleaseCard(sc);
+  cardslots.Release();
 }
 
 bool cSmartCards::ListCard(int num, char *str, int len)
 {
-  cSmartCardSlot *slot=GetSlot(num);
-  if(!slot) return false;
+  cSmartCardSlot *slot=cardslots.GetSlot(num);
   str[0]=0;
-  mutex.Lock();
-  cSmartCard *sc=slot->Card;
-  if(sc) {
-    if(!sc->GetCardIdStr(str,len)) {
-      cSmartCardLink *scl=first;
-      while(scl) {
-        if(scl->id==slot->CardId) {
-          strn0cpy(str,scl->name,len);
-          break;
-          }
-        scl=scl->next;
-        }
-      }
-    }
-  mutex.Unlock();
-  return true;
+  bool res=false;
+  if(slot) { slot->GetCardIdStr(str,len); res=true; }
+  cardslots.Release();
+  return res;
 }
 
 bool cSmartCards::CardInfo(int num, char *str, int len)
 {
+  cSmartCardSlot *slot=cardslots.GetSlot(num);
+  str[0]=0;
   bool res=false;
-  cSmartCardSlot *slot=GetSlot(num);
-  if(slot) {
-    str[0]=0;
-    mutex.Lock();
-    cSmartCard *sc=slot->Card;
-    if(sc) res=sc->GetCardInfoStr(str,len);
-    mutex.Unlock();
-    }
+  if(slot) res=slot->GetCardInfoStr(str,len);
+  cardslots.Release();
   return res;
 }
 
 void cSmartCards::CardReset(int num)
 {
-  cSmartCardSlot *slot=GetSlot(num);
-  if(slot) {
-    mutex.Lock();
-    cSmartCard *sc=slot->Card;
-    if(sc) sc->TriggerReset();
-    mutex.Unlock();
-    }
+  cSmartCardSlot *slot=cardslots.GetSlot(num);
+  if(slot) slot->TriggerReset();
+  cardslots.Release();
 }
index 63c1ed94eb7139789da9f9f4b01180b7bfcba8cd..eac4ae15b8a819eb9b3b237d35b361363f8a2679 100644 (file)
@@ -40,8 +40,8 @@
 
 // ----------------------------------------------------------------
 
-class cSerial;
 class cSmartCards;
+class cSmartCardSlot;
 
 // ----------------------------------------------------------------
 
@@ -74,18 +74,6 @@ public:
 
 // ----------------------------------------------------------------
 
-class cSmartCardDatas : public cStructList<cSmartCardData> {
-protected:
-  virtual cStructItem *ParseLine(char *line);
-public:
-  cSmartCardDatas(void);
-  cSmartCardData *Find(cSmartCardData *param);
-  };
-
-extern cSmartCardDatas carddatas;
-
-// ----------------------------------------------------------------
-
 #define SM_NONE 0
 #define SM_8E2  1
 #define SM_8O2  2
@@ -118,18 +106,14 @@ struct Atr {
   unsigned char hist[MAX_HIST];
   };
 
-class cSmartCard : protected cMutex {
-friend class cSmartCards;
+class cSmartCard : public cMutex {
+friend class cSmartCardSlot;
 private:
-  cSerial *ser;
+  cSmartCardSlot *slot;
+  int slotnum;
   const struct CardConfig *cfg;
   const struct StatusMsg *msg;
-  bool cardUp, needsReset;
-  int id;
-  //
-  int Procedure(unsigned char ins, int restLen);
-  int Read(unsigned char *data, int len, int to=0);
-  int Write(const unsigned char *data, int len);
+  bool cardUp;
 protected:
   const struct Atr *atr;
   unsigned char sb[SB_LEN];
@@ -141,11 +125,8 @@ protected:
   bool IsoRead(const unsigned char *cmd, unsigned char *data);
   bool IsoWrite(const unsigned char *cmd, const unsigned char *data);
   bool Status(void);
-  bool Test(bool res);
   void NewCardConfig(const struct CardConfig *Cfg);
   int CheckSctLen(const unsigned char *data, int off);
-  void TriggerReset(void) { needsReset=true; }
-  static void Invert(unsigned char *data, int n);
 public:
   cSmartCard(const struct CardConfig *Cfg, const struct StatusMsg *Msg);
   virtual ~cSmartCard() {};
@@ -154,37 +135,24 @@ public:
   virtual bool Update(int pid, int caid, const unsigned char *data) { return false; }
   virtual bool CanHandle(unsigned short CaId) { return true; }
   //
-  bool Setup(cSerial *Ser, const struct Atr *Atr, int Id);
-  static bool ParseAtr(struct Atr *atr, int id, int clock);
+  bool Setup(cSmartCardSlot *Slot, int sermode, const struct Atr *Atr);
   bool CardUp(void) { return cardUp; }
-  bool NeedsReset(void) { return needsReset; }
   bool GetCardIdStr(char *str, int len);
   bool GetCardInfoStr(char *str, int len);
   };
 
 // ----------------------------------------------------------------
 
-class cSmartCardSlot : public cStructItem {
-public:
-  cSmartCardSlot(int num);
-  ~cSmartCardSlot();
-  //
-  cSerial *Serial;
-  bool Dead;
-  cSmartCard *Card;
-  int CardId, UseCount, SlotNum, Clock;
-  struct Atr Atr;
-  };
-
-// ----------------------------------------------------------------
-
 class cSmartCardLink {
-public:
+friend class cSmartCards;
+private:
   cSmartCardLink *next;
   const char *name;
   int id;
 public:
   cSmartCardLink(const char *Name, int Id);
+  const char *Name(void) { return name; }
+  int Id(void) { return id; }
   virtual ~cSmartCardLink() {}
   virtual cSmartCard *Create(void)=0;
   virtual cSmartCardData *CreateData(void) { return 0; }
@@ -192,35 +160,23 @@ public:
 
 // ----------------------------------------------------------------
 
-class cSmartCards : private cThread, public cStructListPlain<cSmartCardSlot> {
+class cSmartCards {
 friend class cSmartCardLink;
-friend class cSmartCardDatas;
 private:
   static cSmartCardLink *first;
-  cMutex mutex;
-  cCondVar cond;
-  bool firstRun;
   //
   static void Register(cSmartCardLink *scl);
-  bool CardInserted(cSerial *ser);
-  bool CardReset(cSmartCardSlot *port);
-  int Reset(cSmartCardSlot *port);
-  bool DoPTS(cSmartCardSlot *port);
-  void SetPort(cSmartCardSlot *port, cSmartCard *sc, int id, bool dead);
-  cSmartCardSlot *GetSlot(int num);
-protected:
-  virtual void Action(void);
-  virtual void PreLoad(void);
-  virtual bool ParseLinePlain(const char *line);
 public:
-  cSmartCards(void);
   void Shutdown(void);
+  void Disable(void);
+  static cSmartCardLink *First(void) { return first; }
+  static cSmartCardLink *Next(cSmartCardLink *scl) { return scl->next; }
   // to be called ONLY from a system class!
+  cSmartCardData *FindCardData(cSmartCardData *param);
   bool HaveCard(int id);
   cSmartCard *LockCard(int id);
   void ReleaseCard(cSmartCard *sc);
   // to be called ONLY from frontend thread!
-  void LaunchWatcher(void);
   bool ListCard(int num, char *str, int len);
   bool CardInfo(int num, char *str, int len);
   void CardReset(int num);
index af38f162cde80d43ea45cfbab6642df58ab0ba2d..9f1688999a4b040a43ce6794e18be51aa25facf4 100644 (file)
@@ -304,7 +304,7 @@ bool cSmartCardCryptoworks::Init(void)
   if(ReadRecord(buff,0x9E)>=66) {
     HEXDUMP(L_SC_EXTRA,&buff[2],64,"card ISK");
     cSmartCardDataCryptoworks cd(dtIPK,Caid);
-    cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)carddatas.Find(&cd);
+    cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)smartcards.FindCardData(&cd);
     if(entry) {
       PRINTF(L_SC_EXTRA,"got IPK from smartcard.conf");
       if(rsa.RSA(&buff[2],&buff[2],64,exp,entry->key,false)>0) {
@@ -322,7 +322,7 @@ bool cSmartCardCryptoworks::Init(void)
     }
   if(!ucpkValid) {
     cSmartCardDataCryptoworks cd(dtUCPK,serial);
-    cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)carddatas.Find(&cd);
+    cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)smartcards.FindCardData(&cd);
     if(entry) {
       BN_copy(ucpk,entry->key);
       ucpkValid=true;
@@ -418,7 +418,7 @@ bool cSmartCardCryptoworks::Init(void)
       }
     if(!pinOK) {
       cSmartCardDataCryptoworks cd(dtPIN,serial);
-      cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)carddatas.Find(&cd);
+      cSmartCardDataCryptoworks *entry=(cSmartCardDataCryptoworks *)smartcards.FindCardData(&cd);
       if(entry) {
         memcpy(&buff[2],entry->pin,4);
         pinOK=true;
index 628b90d5697205eee901ffefcd47ce0cd795b667..2a316f568c76ac6af8d08c081c13a23e4b422348 100644 (file)
@@ -462,10 +462,10 @@ bool cSmartCardIrdeto::Init(void)
   cSmartCardDataIrdeto *entry=0;
   if(!doPlain) {
     cSmartCardDataIrdeto cd(ACS,caId);
-    if(!(entry=(cSmartCardDataIrdeto *)carddatas.Find(&cd))) {
+    if(!(entry=(cSmartCardDataIrdeto *)smartcards.FindCardData(&cd))) {
       PRINTF(L_GEN_WARN,"didn't find Irdeto card specific certificate, falling back to default");
       cSmartCardDataIrdeto cd(-1,-1);
-      if(!(entry=(cSmartCardDataIrdeto *)carddatas.Find(&cd))) {
+      if(!(entry=(cSmartCardDataIrdeto *)smartcards.FindCardData(&cd))) {
         PRINTF(L_GEN_WARN,"didn't find default Irdeto certificate, please add one");
         if(ACS!=0x0384) return false;
         PRINTF(L_GEN_WARN,"trying pre-coded ACS 384 challenge. This mode is DEPRECATED. There ARE valid certificates for these cards available!");
index ec16d096705be4cda7109df953c74408983f0084..e0feeac0d52b2769ff628eb9df44d5e82c5fe6b2 100644 (file)
@@ -385,7 +385,7 @@ bool cSmartCardNagra::Init(void)
   bool sessOk=false;
   if(buff[5]!=0 && irdProvId==((buff[10]*256)|buff[11])) { // prepare DT08 data
     cSmartCardDataNagra cd(irdProvId,true);
-    if(!(entry=(cSmartCardDataNagra *)carddatas.Find(&cd))) {
+    if(!(entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd))) {
       PRINTF(L_GEN_WARN,"didn't find smartcard Nagra IRD modulus");
       }
     else {
@@ -395,7 +395,7 @@ bool cSmartCardNagra::Init(void)
     }
   else {
     cSmartCardDataNagra cd(irdProvId);
-    if(!(entry=(cSmartCardDataNagra *)carddatas.Find(&cd))) {
+    if(!(entry=(cSmartCardDataNagra *)smartcards.FindCardData(&cd))) {
       PRINTF(L_GEN_WARN,"didn't find smartcard Nagra CAM modulus");
       }
     else {
index c0bbd29a2696ec3631d2398a8ffa563a6103af46..3080e88a484df21a5636278242f408a2db188801 100644 (file)
@@ -566,7 +566,7 @@ bool cSmartCardVideoGuard2::Init(void)
       }
   if(!boxidOK) {
     cSmartCardDataVideoGuard2 cd(dtBoxId);
-    cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)carddatas.Find(&cd);
+    cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd);
     if(entry) {
       memcpy(&boxID,entry->boxid,sizeof(boxID));
       boxidOK=true;
@@ -603,7 +603,7 @@ bool cSmartCardVideoGuard2::Init(void)
   PRINTF(L_SC_INIT,"cardtype: %c%c.%d boxID %s caid %04x cardID %s",atr->hist[10],atr->hist[11],atr->hist[12],HexStr(str,boxID,4),CAID,HexStr(str2,cardID,4));
 
   cSmartCardDataVideoGuard2 cd(dtSeed);
-  cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)carddatas.Find(&cd);
+  cSmartCardDataVideoGuard2 *entry=(cSmartCardDataVideoGuard2 *)smartcards.FindCardData(&cd);
   if(!entry) {
     PRINTF(L_SC_ERROR,"no NDS seed available");
     return false;
index 1a339c722e963ed23afc54eb14dc2a35bd97ed98..db59a91be66f4a22fe0405c156e84cfdd582b1fa 100644 (file)
@@ -23,7 +23,7 @@ DEFINES  = -DAPIVERSNUM=$(APIVERSNUM) -DAPIVERSION='"$(APIVERSION)"' -DSCAPIVERS
 
 OBJS = misc.o log.o data.o crypto.o parse.o system.o system-common.o smartcard.o network.o filter.o version.o
 SHAREDOBJS = compat.o $(VDRDIR)/tools.o $(VDRDIR)/thread.o
-LIBS = -lpthread -ljpeg -lcrypto
+LIBS = -lpthread -lrt -ljpeg -lcrypto
 DYNLIBS = -ldl $(VDRDIR)/libsi/libsi.a
 
 NOBJS  = $(patsubst %.o,../%.o,$(OBJS))
index e731e91d8a89de18f1026312441c6263c5859eaa..0099986a17a67df18ba3eca0908ed09bf5e520e4 100644 (file)
@@ -61,11 +61,6 @@ void InitAll(const char *cfgdir)
   if(Feature.KeyFile() && keys.Count()<1)
     PRINTF(L_GEN_ERROR,"no keys loaded for softcam!");
   if(!cSystems::Init(cfgdir)) exit(2);
-
-#ifdef DEFAULT_PORT
-  smartcards.AddPort(DEFAULT_PORT);
-#endif
-  smartcards.LaunchWatcher();
 }
 
 void LogAll(void)