--- /storage/sc/cam.c
+++ /storage/sc-nas/cam.c
@@ -39,7 +39,13 @@
 #include "misc.h"
 #include "log-core.h"
 #ifndef SASC
+#ifndef LIBDVBCSA
 #include "FFdecsa/FFdecsa.h"
+#else
+extern "C" { 
+#include <dvbcsa/dvbcsa.h>
+}
+#endif
 #endif
 
 #define IDLE_SLEEP          0 // idleTime when sleeping
@@ -1772,7 +1778,9 @@
 void cCiFrame::Put(void)
 {
   if(rb && mem) {
-    *((short *)mem)=len;
+    // *((short *)mem)=len; //does not work when /proc/cpu/alignment=0
+    *mem     = len & 0xff;
+    *(mem+1) = len >> 8;
     rb->Put(mem,len+LEN_OFF);
     }
 }
@@ -1784,7 +1792,8 @@
     unsigned char *data=rb->Get(c);
     if(data) {
       if(c>LEN_OFF) {
-        int s=*((short *)data);
+        // int s=*((short *)data); //does not work when /proc/cpu/alignment=0
+        int s = *data + (*(data+1) << 8);
         if(c>=s+LEN_OFF) {
           l=glen=s;
           return data+LEN_OFF;
@@ -2794,15 +2803,23 @@
 #define FL_ODD_GOOD  2
 #define FL_ACTIVITY  4
 
-
 cDeCSA::cDeCSA(const char *DevId)
 :stall(MAX_STALL_MS)
 {
   devId=DevId;
+  #ifndef LIBDVBCSA
   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));
+  #else
+  cs = dvbcsa_bs_batch_size();
+  //PRINTF(L_CORE_CSA,"%d: batch_size=%d", cardindex, cs);
+  cs_tsbbatch_even = (dvbcsa_bs_batch_s *) malloc((cs + 1) * sizeof(struct dvbcsa_bs_batch_s));
+  cs_tsbbatch_odd = (dvbcsa_bs_batch_s *) malloc((cs + 1) * sizeof(struct dvbcsa_bs_batch_s));
+  memset(cs_key_even, 0, sizeof(cs_key_even));
+  memset(cs_key_odd, 0, sizeof(cs_key_odd));
+  #endif
   memset(pidmap,0,sizeof(pidmap));
   ResetState();
 }
@@ -2810,8 +2827,19 @@
 cDeCSA::~cDeCSA()
 {
   for(int i=0; i<MAX_CSA_IDX; i++)
+  #ifndef LIBDVBCSA
     if(keys[i]) free_key_struct(keys[i]);
   free(range);
+  #else
+  {
+    if (cs_key_even[i])
+      dvbcsa_bs_key_free(cs_key_even[i]);
+    if (cs_key_odd[i])
+      dvbcsa_bs_key_free(cs_key_odd[i]);
+  }
+  free(cs_tsbbatch_even);
+  free(cs_tsbbatch_odd);
+  #endif
 }
 
 void cDeCSA::ResetState(void)
@@ -2819,7 +2847,9 @@
   PRINTF(L_CORE_CSA,"%s: reset state",devId);
   memset(even_odd,0,sizeof(even_odd));
   memset(flags,0,sizeof(flags));
+  #ifndef LIBDVBCSA
   lastData=0;
+  #endif
 }
 
 void cDeCSA::SetActive(bool on)
@@ -2831,8 +2861,16 @@
 
 bool cDeCSA::GetKeyStruct(int idx)
 {
+  #ifndef LIBDVBCSA
   if(!keys[idx]) keys[idx]=get_key_struct();
   return keys[idx]!=0;
+  #else
+  if (!cs_key_even[idx])
+    cs_key_even[idx] = dvbcsa_bs_key_alloc();
+  if (!cs_key_odd[idx])
+    cs_key_odd[idx] = dvbcsa_bs_key_alloc();
+  return (cs_key_even[idx] != 0) && (cs_key_odd[idx] != 0);
+  #endif
 }
 
 bool cDeCSA::SetDescr(ca_descr_t *ca_descr, bool initial)
@@ -2850,13 +2888,21 @@
       }
     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) {
+      #ifndef LIBDVBCSA
       set_even_control_word(keys[idx],ca_descr->cw);
+      #else
+      dvbcsa_bs_key_set(ca_descr->cw, cs_key_even[idx]);
+      #endif
       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 {
+      #ifndef LIBDVBCSA
       set_odd_control_word(keys[idx],ca_descr->cw);
+      #else
+      dvbcsa_bs_key_set(ca_descr->cw, cs_key_odd[idx]);
+      #endif
       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();
@@ -2875,24 +2921,72 @@
   return true;
 }
 
+#ifdef LIBDVBCSA
+unsigned char ts_packet_get_payload_offset(unsigned char *ts_packet)
+{
+  if (ts_packet[0] != TS_SYNC_BYTE)
+    return 0;
+
+  unsigned char adapt_field   = (ts_packet[3] &~ 0xDF) >> 5; // 11x11111
+  unsigned char payload_field = (ts_packet[3] &~ 0xEF) >> 4; // 111x1111
+
+  if (!adapt_field && !payload_field)     // Not allowed
+    return 0;
+
+  if (adapt_field)
+  {
+    unsigned char adapt_len = ts_packet[4];
+    if (payload_field && adapt_len > 182) // Validity checks
+      return 0;
+    if (!payload_field && adapt_len > 183)
+      return 0;
+    if (adapt_len + 4 > TS_SIZE)  // adaptation field takes the whole packet
+      return 0;
+    return 4 + 1 + adapt_len;     // ts header + adapt_field_len_byte + adapt_field_len
+  }
+  else
+  {
+    return 4; // No adaptation, data starts directly after TS header
+  }
+}
+#endif
+
+
+
 bool cDeCSA::Decrypt(unsigned char *data, int len, bool force)
 {
   cMutexLock lock(&mutex);
+  #ifndef LIBDVBCSA
   int r=-2, ccs=0, currIdx=-1;
   bool newRange=true;
   range[0]=0;
+  #else
+  int ccs = 0, currIdx = -1;
+  int payload_len, offset;
+  int cs_fill_even = 0;
+  int cs_fill_odd = 0;
+  #endif
   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);
+      #ifndef LIBDVBCSA
       if(ccs) force=true;             // prevent buffer stall
+      #endif
       break;
       }
     unsigned int ev_od=data[l+3]&0xC0;
     if(ev_od==0x80 || ev_od==0xC0) { // encrypted
+      #ifdef LIBDVBCSA
+      offset = ts_packet_get_payload_offset(data + l);
+      payload_len = TS_SIZE - offset;
+      #endif
       int idx=pidmap[((data[l+1]<<8)+data[l+2])&(MAX_CSA_PIDS-1)];
       if(currIdx<0 || idx==currIdx) { // same or no index
+        #ifdef LIBDVBCSA
+        data[l + 3] &= 0x3f;    // consider it decrypted now
+        #endif
         currIdx=idx;
         if(ccs==0 && ev_od!=even_odd[idx]) {
           even_odd[idx]=ev_od;
@@ -2917,20 +3011,38 @@
             else PRINTF(L_CORE_CSA,"%s.%d: not active. wait skipped",devId,idx);
             }
           }
+        #ifndef LIBDVBCSA
         if(newRange) {
           r+=2; newRange=false;
           range[r]=&data[l];
           range[r+2]=0;
           }
         range[r+1]=&data[l+TS_SIZE];
+        #else
+        if (((ev_od & 0x40) >> 6) == 0)
+        {
+          cs_tsbbatch_even[cs_fill_even].data = &data[l + offset];
+          cs_tsbbatch_even[cs_fill_even].len = payload_len;
+          cs_fill_even++;
+        }
+        else
+        {
+          cs_tsbbatch_odd[cs_fill_odd].data = &data[l + offset];
+          cs_tsbbatch_odd[cs_fill_odd].len = payload_len;
+          cs_fill_odd++;
+        }
+        #endif
         if(++ccs>=cs) break;
         }
+      #ifndef LIBDVBCSA
       else newRange=true;             // other index, create hole
+      #endif
       }
     else {                            // unencrypted
       // nothing, we don't create holes for unencrypted packets
       }
     }
+  #ifndef LIBDVBCSA
   int scanTS=l/TS_SIZE;
   int stallP=ccs*100/scanTS;
 
@@ -2977,6 +3089,26 @@
       }
     else PRINTF(L_CORE_CSAVERB,"%s.%d: incomplete ccs=%3d cs=%3d",devId,currIdx,ccs,cs);
     }
+  #else
+  if (GetKeyStruct(currIdx))
+  {
+    if (cs_fill_even)
+    {
+      cs_tsbbatch_even[cs_fill_even].data = NULL;
+      dvbcsa_bs_decrypt(cs_key_even[currIdx], cs_tsbbatch_even, 184);
+      cs_fill_even = 0;
+    }
+    if (cs_fill_odd)
+    {
+      cs_tsbbatch_odd[cs_fill_odd].data = NULL;
+      dvbcsa_bs_decrypt(cs_key_odd[currIdx], cs_tsbbatch_odd, 184);
+      cs_fill_odd = 0;
+    }
+
+    stall.Set(MAX_STALL_MS);
+    return true;
+  }
+  #endif
   return false;
 }
 
