SASC
DVBSoftCAM

device.c

Go to the documentation of this file.
00001 /*
00002  * Softcam plugin to VDR (C++)
00003  *
00004  * This code is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This code is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
00018  */
00019 
00020 #include <stdlib.h>
00021 #include <stdio.h>
00022 #include <errno.h>
00023 #include <sys/ioctl.h>
00024 #include <sys/time.h>
00025 #include <dlfcn.h>
00026 
00027 #include <vdr/channels.h>
00028 #include <vdr/ci.h>
00029 #include <vdr/dvbdevice.h>
00030 #include <vdr/thread.h>
00031 
00032 #ifndef SASC
00033 #include <vdr/dvbci.h>
00034 #include "FFdecsa/FFdecsa.h"
00035 #endif //!SASC
00036 
00037 #include "device.h"
00038 #include "cam.h"
00039 #include "scsetup.h"
00040 #include "system.h"
00041 #include "data.h"
00042 #include "override.h"
00043 #include "misc.h"
00044 #include "log-core.h"
00045 
00046 // -- cDeCsaTSBuffer -----------------------------------------------------------
00047 
00048 #ifndef SASC
00049 
00050 cDeCsaTSBuffer::cDeCsaTSBuffer(int File, int Size, int CardIndex, cDeCSA *DeCsa, bool ScActive)
00051 {
00052   SetDescription("TS buffer on device %d", CardIndex);
00053   f=File; size=Size; cardIndex=CardIndex; decsa=DeCsa;
00054   delivered=false;
00055   ringBuffer=new cRingBufferLinear(Size,TS_SIZE,true,"FFdecsa-TS");
00056   ringBuffer->SetTimeouts(100,100);
00057   if(decsa) decsa->SetActive(true);
00058   SetActive(ScActive);
00059   Start();
00060 }
00061 
00062 cDeCsaTSBuffer::~cDeCsaTSBuffer()
00063 {
00064   Cancel(3);
00065   if(decsa) decsa->SetActive(false);
00066   delete ringBuffer;
00067 }
00068 
00069 void cDeCsaTSBuffer::SetActive(bool ScActive)
00070 {
00071   scActive=ScActive;
00072 }
00073 
00074 void cDeCsaTSBuffer::Action(void)
00075 {
00076   if(ringBuffer) {
00077     bool firstRead=true;
00078     cPoller Poller(f);
00079     while(Running()) {
00080       if(firstRead || Poller.Poll(100)) {
00081         firstRead=false;
00082         int r=ringBuffer->Read(f);
00083         if(r<0 && FATALERRNO) {
00084           if(errno==EOVERFLOW)
00085             esyslog("ERROR: driver buffer overflow on device %d",cardIndex);
00086           else { LOG_ERROR; break; }
00087           }
00088         }
00089       }
00090     }
00091 }
00092 
00093 uchar *cDeCsaTSBuffer::Get(void)
00094 {
00095   int Count=0;
00096   if(delivered) { ringBuffer->Del(TS_SIZE); delivered=false; }
00097   uchar *p=ringBuffer->Get(Count);
00098   if(p && Count>=TS_SIZE) {
00099     if(*p!=TS_SYNC_BYTE) {
00100       for(int i=1; i<Count; i++)
00101         if(p[i]==TS_SYNC_BYTE &&
00102            (i+TS_SIZE==Count || (i+TS_SIZE>Count && p[i+TS_SIZE]==TS_SYNC_BYTE)) ) { Count=i; break; }
00103       ringBuffer->Del(Count);
00104       esyslog("ERROR: skipped %d bytes to sync on TS packet on device %d",Count,cardIndex);
00105       return NULL;
00106       }
00107 
00108     if(scActive && (p[3]&0xC0)) {
00109       if(decsa) {
00110         if(!decsa->Decrypt(p,Count,false)) {
00111           cCondWait::SleepMs(20);
00112           return NULL;
00113           }
00114         }
00115       else p[3]&=~0xC0; // FF hack
00116       }
00117 
00118     delivered=true;
00119     return p;
00120     }
00121   return NULL;
00122 }
00123 
00124 #endif //!SASC
00125 
00126 // --- cScDevicePlugin ---------------------------------------------------------
00127 
00128 static cSimpleList<cScDevicePlugin> devplugins;
00129 
00130 cScDevicePlugin::cScDevicePlugin(void)
00131 {
00132   devplugins.Add(this);
00133 }
00134 
00135 cScDevicePlugin::~cScDevicePlugin()
00136 {
00137   devplugins.Del(this,false);
00138 }
00139 
00140 // -- cScDvbDevice -------------------------------------------------------------
00141 
00142 #ifndef SASC
00143 
00144 #define SCDEVICE cScDvbDevice
00145 #define DVBDEVICE cDvbDevice
00146 #if APIVERSNUM < 10711
00147 #define OWN_FULLTS
00148 #define OWN_SETCA
00149 #endif
00150 #include "device-tmpl.c"
00151 
00152 #if APIVERSNUM < 10711
00153 bool cScDvbDevice::CheckFullTs(void)
00154 {
00155   return IsPrimaryDevice() && HasDecoder();
00156 }
00157 
00158 bool cScDvbDevice::SetCaDescr(ca_descr_t *ca_descr, bool initial)
00159 {
00160   cMutexLock lock(&cafdMutex);
00161   return ioctl(fd_ca,CA_SET_DESCR,ca_descr)>=0;
00162 }
00163 
00164 bool cScDvbDevice::SetCaPid(ca_pid_t *ca_pid)
00165 {
00166   cMutexLock lock(&cafdMutex);
00167   return ioctl(fd_ca,CA_SET_PID,ca_pid)>=0;
00168 }
00169 #endif //APIVERSNUM < 10711
00170 
00171 // -- cScDvbDevicePlugin -------------------------------------------------------
00172 
00173 class cScDvbDevicePlugin : public cScDevicePlugin {
00174 public:
00175   virtual cDevice *Probe(int Adapter, int Frontend, uint32_t SubSystemId);
00176   virtual bool LateInit(cDevice *dev);
00177   virtual bool EarlyShutdown(cDevice *dev);
00178 #if APIVERSNUM < 10711
00179   virtual bool SetCaDescr(cDevice *dev, ca_descr_t *ca_descr, bool initial);
00180   virtual bool SetCaPid(cDevice *dev, ca_pid_t *ca_pid);
00181 #endif
00182   };
00183 
00184 cDevice *cScDvbDevicePlugin::Probe(int Adapter, int Frontend, uint32_t SubSystemId)
00185 {
00186   PRINTF(L_GEN_DEBUG,"creating standard device %d/%d",Adapter,Frontend);
00187   return new cScDvbDevice(this,Adapter,Frontend,cScDevices::DvbOpen(DEV_DVB_CA,Adapter,Frontend,O_RDWR));
00188 }
00189 
00190 bool cScDvbDevicePlugin::LateInit(cDevice *dev)
00191 {
00192   cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev);
00193   if(d) d->LateInit();
00194   return d!=0;
00195 }
00196 
00197 bool cScDvbDevicePlugin::EarlyShutdown(cDevice *dev)
00198 {
00199   cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev);
00200   if(d) d->EarlyShutdown();
00201   return d!=0;
00202 }
00203 
00204 #if APIVERSNUM < 10711
00205 bool cScDvbDevicePlugin::SetCaDescr(cDevice *dev, ca_descr_t *ca_descr, bool initial)
00206 {
00207   cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev);
00208   if(d) return d->SetCaDescr(ca_descr,initial);
00209   return false;
00210 }
00211 
00212 bool cScDvbDevicePlugin::SetCaPid(cDevice *dev, ca_pid_t *ca_pid)
00213 {
00214   cScDvbDevice *d=dynamic_cast<cScDvbDevice *>(dev);
00215   if(d) return d->SetCaPid(ca_pid);
00216   return d!=0;
00217 }
00218 #endif //APIVERSNUM < 10711
00219 
00220 // --- cScDeviceProbe ----------------------------------------------------------
00221 
00222 #if APIVERSNUM >= 10711
00223 
00224 class cScDeviceProbe : public cDvbDeviceProbe {
00225 private:
00226   static cScDeviceProbe *probe;
00227 public:
00228   virtual bool Probe(int Adapter, int Frontend);
00229   static void Install(void);
00230   static void Remove(void);
00231 #if APIVERSNUM < 10719
00232   uint32_t GetSubsystemId(int Adapter, int Frontend);
00233 #endif
00234   };
00235 
00236 cScDeviceProbe *cScDeviceProbe::probe=0;
00237 
00238 void cScDeviceProbe::Install(void)
00239 {
00240   if(!probe) probe=new cScDeviceProbe;
00241 }
00242 
00243 void cScDeviceProbe::Remove(void)
00244 {
00245   delete probe; probe=0;
00246 }
00247 
00248 bool cScDeviceProbe::Probe(int Adapter, int Frontend)
00249 {
00250   uint32_t subid=GetSubsystemId(Adapter,Frontend);
00251   PRINTF(L_GEN_DEBUG,"capturing device %d/%d (subsystem ID %08x)",Adapter,Frontend,subid);
00252   for(cScDevicePlugin *dp=devplugins.First(); dp; dp=devplugins.Next(dp))
00253     if(dp->Probe(Adapter,Frontend,subid)) return true;
00254   return false;
00255 }
00256 
00257 #if APIVERSNUM < 10719
00258 uint32_t cScDeviceProbe::GetSubsystemId(int Adapter, int Frontend)
00259 {
00260   cString FileName;
00261   cReadLine ReadLine;
00262   FILE *f = NULL;
00263   uint32_t SubsystemId = 0;
00264   FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend);
00265   if ((f = fopen(FileName, "r")) != NULL) {
00266      if (char *s = ReadLine.Read(f))
00267         SubsystemId = strtoul(s, NULL, 0) << 16;
00268      fclose(f);
00269      }
00270   FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend);
00271   if ((f = fopen(FileName, "r")) != NULL) {
00272      if (char *s = ReadLine.Read(f))
00273         SubsystemId |= strtoul(s, NULL, 0);
00274      fclose(f);
00275      }
00276   return SubsystemId;
00277 }
00278 #endif //APIVERSNUM < 10719
00279 
00280 #endif //APIVERSNUM >= 10711
00281 
00282 #endif //!SASC
00283 
00284 // -- cScDevices ---------------------------------------------------------------
00285 
00286 int cScDevices::budget=0;
00287 
00288 void cScDevices::DvbName(const char *Name, int a, int f, char *buffer, int len)
00289 {
00290   snprintf(buffer,len,"%s%d/%s%d",DEV_DVB_ADAPTER,a,Name,f);
00291 }
00292 
00293 int cScDevices::DvbOpen(const char *Name, int a, int f, int Mode, bool ReportError)
00294 {
00295   char FileName[128];
00296   DvbName(Name,a,f,FileName,sizeof(FileName));
00297   int fd=open(FileName,Mode);
00298   if(fd<0 && ReportError) LOG_ERROR_STR(FileName);
00299   return fd;
00300 }
00301 
00302 #ifndef SASC
00303 
00304 #if APIVERSNUM < 10711
00305 static int *vdr_nci=0, *vdr_ud=0, vdr_save_ud;
00306 #endif
00307 
00308 void cScDevices::OnPluginLoad(void)
00309 {
00310 #if APIVERSNUM >= 10711
00311   PRINTF(L_GEN_DEBUG,"using new 1.7.11+ capture code");
00312   cScDeviceProbe::Install();
00313 #else
00314   PRINTF(L_GEN_DEBUG,"using old pre1.7.11 capture code");
00315 /*
00316   This is an extremly ugly hack to access VDRs device scan parameters, which are
00317   protected in this context. Heavily dependant on the actual symbol names
00318   created by the compiler. May fail in any future version!
00319 
00320   To get the actual symbol names of your VDR binary you may use the command:
00321   objdump -T <path-to-vdr>/vdr | grep -E "(useDevice|nextCardIndex)"
00322   Insert the symbol names below.
00323 */
00324 #if __GNUC__ >= 3
00325   vdr_nci=(int *)dlsym(RTLD_DEFAULT,"_ZN7cDevice13nextCardIndexE");
00326   vdr_ud =(int *)dlsym(RTLD_DEFAULT,"_ZN7cDevice9useDeviceE");
00327 #else
00328   vdr_nci=(int *)dlsym(RTLD_DEFAULT,"_7cDevice.nextCardIndex");
00329   vdr_ud =(int *)dlsym(RTLD_DEFAULT,"_7cDevice.useDevice");
00330 #endif
00331   if(vdr_nci && vdr_ud) { vdr_save_ud=*vdr_ud; *vdr_ud=1<<30; }
00332 #endif
00333   // default device plugin must be last in the list
00334   new cScDvbDevicePlugin;
00335 }
00336 
00337 void cScDevices::OnPluginUnload(void)
00338 {
00339 #if APIVERSNUM >= 10711
00340   cScDeviceProbe::Remove();
00341 #endif
00342 }
00343 
00344 bool cScDevices::Initialize(void)
00345 {
00346 #if APIVERSNUM >= 10711
00347   return true;
00348 #else
00349   if(!vdr_nci || !vdr_ud) {
00350     PRINTF(L_GEN_ERROR,"Failed to locate VDR symbols. Plugin not operable");
00351     return false;
00352     }
00353   if(NumDevices()>0) {
00354     PRINTF(L_GEN_ERROR,"Number of devices != 0 on init. Put SC plugin first on VDR commandline! Aborting.");
00355     return false;
00356     }
00357   *vdr_nci=0; *vdr_ud=vdr_save_ud;
00358 
00359   int i, found=0;
00360   for(i=0; i<MAXDVBDEVICES; i++) {
00361     if(UseDevice(NextCardIndex())) {
00362       char name[128];
00363       cScDevices::DvbName(DEV_DVB_FRONTEND,i,0,name,sizeof(name));
00364       if(access(name,F_OK)==0) {
00365         PRINTF(L_GEN_DEBUG,"probing %s",name);
00366         int f=open(name,O_RDONLY);
00367         if(f>=0) {
00368           close(f);
00369           PRINTF(L_GEN_DEBUG,"capturing device %d",i);
00370           devplugins.First()->Probe(i,0,0);
00371           found++;
00372           }
00373         else {
00374           if(errno!=ENODEV && errno!=EINVAL) PRINTF(L_GEN_ERROR,"open %s failed: %s",name,strerror(errno));
00375           break;
00376           }
00377         }
00378       else {
00379         if(errno!=ENOENT) PRINTF(L_GEN_ERROR,"access %s failed: %s",name,strerror(errno));
00380         break;
00381         }
00382       }
00383     else NextCardIndex(1);
00384     }
00385   NextCardIndex(MAXDVBDEVICES-i);
00386   if(found>0) PRINTF(L_GEN_INFO,"captured %d video device%s",found,found>1 ? "s" : "");
00387   else PRINTF(L_GEN_INFO,"no DVB device captured");
00388   return found>0;
00389 #endif
00390 }
00391 
00392 void cScDevices::Startup(void)
00393 {
00394   if(ScSetup.ForceTransfer)
00395     SetTransferModeForDolbyDigital(2);
00396   for(int n=cDevice::NumDevices(); --n>=0;) {
00397     cDevice *dev=cDevice::GetDevice(n);
00398     for(cScDevicePlugin *dp=devplugins.First(); dp; dp=devplugins.Next(dp))
00399       if(dp->LateInit(dev)) break;
00400     }
00401 }
00402 
00403 void cScDevices::Shutdown(void)
00404 {
00405   for(int n=cDevice::NumDevices(); --n>=0;) {
00406     cDevice *dev=cDevice::GetDevice(n);
00407     for(cScDevicePlugin *dp=devplugins.First(); dp; dp=devplugins.Next(dp))
00408       if(dp->EarlyShutdown(dev)) break;
00409     }
00410 }
00411 
00412 void cScDevices::SetForceBudget(int n)
00413 {
00414    if(n>=0 && n<MAXDVBDEVICES) budget|=(1<<n);
00415 }
00416 
00417 bool cScDevices::ForceBudget(int n)
00418 {
00419    return budget && (budget&(1<<n));
00420 }
00421 
00422 #else //!SASC
00423 
00424 void cScDevices::OnPluginLoad(void) {}
00425 void cScDevices::OnPluginUnload(void) {}
00426 bool cScDevices::Initialize(void) { return true; }
00427 void cScDevices::Startup(void) {}
00428 void cScDevices::Shutdown(void) {}
00429 void cScDevices::SetForceBudget(int n) {}
00430 bool cScDevices::ForceBudget(int n) { return true; }
00431 
00432 #endif //!SASC
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines