summaryrefslogtreecommitdiff
path: root/patches
diff options
context:
space:
mode:
authorLars Hanisch <dvb@flensrocker.de>2011-02-02 14:18:45 +0100
committerLars Hanisch <dvb@flensrocker.de>2011-02-02 14:18:45 +0100
commitc03cb92fb43baab9136bd9122d757359e0590fda (patch)
treedbd9851e29274ba4b0189f3f859c1a29d20b8a88 /patches
downloadvdr-plugin-dynamite-c03cb92fb43baab9136bd9122d757359e0590fda.tar.gz
vdr-plugin-dynamite-c03cb92fb43baab9136bd9122d757359e0590fda.tar.bz2
initial commit of version 0.0.5c
Diffstat (limited to 'patches')
-rw-r--r--patches/sc-1.0.0pre-subdevice.patch215
-rw-r--r--patches/vdr-1.7.16-dynamite-subdevice.patch361
2 files changed, 576 insertions, 0 deletions
diff --git a/patches/sc-1.0.0pre-subdevice.patch b/patches/sc-1.0.0pre-subdevice.patch
new file mode 100644
index 0000000..39ca3e5
--- /dev/null
+++ b/patches/sc-1.0.0pre-subdevice.patch
@@ -0,0 +1,215 @@
+diff --git a/device.c b/device.c
+index fe10d5e..b29a993 100644
+--- a/device.c
++++ b/device.c
+@@ -1334,6 +1334,17 @@ bool cScDeviceProbe::Probe(int Adapter, int Frontend)
+ // -- cScDevices ---------------------------------------------------------------
+
+ int cScDevices::budget=0;
++int cScDevices::numScDevices = 0;
++cScDevice *cScDevices::scdevice[MAXDEVICES] = { NULL };
++
++cScDevice *cScDevices::GetScDevice(int CardIndex)
++{
++ for (int n = 0; n < numScDevices; n++) {
++ if (scdevice[n] && (scdevice[n]->CardIndex() == CardIndex))
++ return scdevice[n];
++ }
++ return NULL;
++}
+
+ void cScDevices::DvbName(const char *Name, int a, int f, char *buffer, int len)
+ {
+@@ -1439,16 +1450,16 @@ void cScDevices::Startup(void)
+ {
+ if(ScSetup.ForceTransfer)
+ SetTransferModeForDolbyDigital(2);
+- for(int n=cDevice::NumDevices(); --n>=0;) {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
++ for(int n=cScDevices::numScDevices; --n>=0;) {
++ cScDevice *dev=cScDevices::scdevice[n];
+ if(dev) dev->LateInit();
+ }
+ }
+
+ void cScDevices::Shutdown(void)
+ {
+- for(int n=cDevice::NumDevices(); --n>=0;) {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
++ for(int n=cScDevices::numScDevices; --n>=0;) {
++ cScDevice *dev=cScDevices::scdevice[n];
+ if(dev) dev->EarlyShutdown();
+ }
+ }
+@@ -1490,19 +1501,36 @@ cScDevice::cScDevice(int Adapter, int Frontend, int cafd)
+ :cDvbDevice(Adapter)
+ #endif
+ {
++ lateInit = false;
+ #ifndef SASC
+ decsa=0; tsBuffer=0; cam=0; fullts=false;
+ ciadapter=0; hwciadapter=0;
+ fd_ca=cafd; fd_ca2=dup(fd_ca); fd_dvr=-1;
+ softcsa=(fd_ca<0);
++#ifdef __DYNAMIC_DEVICE_PROBE
++ if (parentDevice)
++ LateInit();
++#endif
+ #else
+ softcsa=fullts=false;
+ cam=new cCam(this,Adapter);
+ #endif // !SASC
++ index = 0;
++ while ((index < cScDevices::numScDevices) && (index < MAXDEVICES) && cScDevices::scdevice[index])
++ index++;
++ if (index < MAXDEVICES) {
++ cScDevices::scdevice[index] = this;
++ if (index == cScDevices::numScDevices)
++ cScDevices::numScDevices++;
++ }
++ else
++ esyslog("too many sc-devices!");
+ }
+
+ cScDevice::~cScDevice()
+ {
++ if ((index >= 0) && (index < MAXDEVICES) && (cScDevices::scdevice[index] == this))
++ cScDevices::scdevice[index] = NULL;
+ #ifndef SASC
+ DetachAllReceivers();
+ Cancel(3);
+@@ -1528,6 +1556,8 @@ void cScDevice::EarlyShutdown(void)
+
+ void cScDevice::LateInit(void)
+ {
++ if (lateInit) return;
++ lateInit = true;
+ int n=CardIndex();
+ if(DeviceNumber()!=n)
+ PRINTF(L_GEN_ERROR,"CardIndex - DeviceNumber mismatch! Put SC plugin first on VDR commandline!");
+@@ -1538,10 +1568,16 @@ void cScDevice::LateInit(void)
+ PRINTF(L_GEN_INFO,"Budget mode forced on card %d",n);
+ softcsa=true;
+ }
+-
++#ifdef __DYNAMIC_DEVICE_PROBE
++ cDevice *cidev = parentDevice ? parentDevice : this;
++ if(fd_ca2>=0) hwciadapter=cDvbCiAdapter::CreateCiAdapter(cidev,fd_ca2);
++ cam=new cCam(this,n);
++ ciadapter=new cScCiAdapter(cidev,n,cam);
++#else
+ if(fd_ca2>=0) hwciadapter=cDvbCiAdapter::CreateCiAdapter(this,fd_ca2);
+ cam=new cCam(this,n);
+ ciadapter=new cScCiAdapter(this,n,cam);
++#endif
+ if(softcsa) {
+ decsa=new cDeCSA(n);
+ if(IsPrimaryDevice() && HasDecoder()) {
+diff --git a/device.h b/device.h
+index 5ad83f9..454d6ea 100644
+--- a/device.h
++++ b/device.h
+@@ -88,6 +88,8 @@ public:
+
+ // ----------------------------------------------------------------
+
++class cScDevice;
++
+ class cScDevices : public cDvbDevice {
+ private:
+ static int budget;
+@@ -106,6 +108,10 @@ public:
+ static bool ForceBudget(int n);
+ static void DvbName(const char *Name, int a, int f, char *buffer, int len);
+ static int DvbOpen(const char *Name, int a, int f, int Mode, bool ReportError=false);
++
++ static int numScDevices;
++ static cScDevice *scdevice[MAXDEVICES];
++ static cScDevice *GetScDevice(int CardIndex);
+ };
+
+ // ----------------------------------------------------------------
+@@ -123,6 +129,8 @@ private:
+ bool softcsa, fullts;
+ cMutex cafdMutex;
+ cTimeMs lastDump;
++ int index;
++ bool lateInit;
+ //
+ #ifndef SASC
+ void LateInit(void);
+diff --git a/sc.c b/sc.c
+index 82960bf..9f01217 100644
+--- a/sc.c
++++ b/sc.c
+@@ -1009,7 +1009,7 @@ void cSoftCAM::Shutdown(void)
+
+ char *cSoftCAM::CurrKeyStr(int CardNum, int num)
+ {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
++ cScDevice *dev=cScDevices::GetScDevice(CardNum);
+ char *str=0;
+ if(dev) {
+ if(dev->Cam()) str=dev->Cam()->CurrentKeyStr(num);
+@@ -1020,8 +1020,8 @@ char *cSoftCAM::CurrKeyStr(int CardNum, int num)
+
+ bool cSoftCAM::Active(bool log)
+ {
+- for(int n=cDevice::NumDevices(); --n>=0;) {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
++ for(int n=cScDevices::numScDevices; --n>=0;) {
++ cScDevice *dev=cScDevices::scdevice[n];
+ if(dev && dev->Cam() && dev->Cam()->Active(log)) return true;
+ }
+ return false;
+@@ -1029,33 +1029,33 @@ bool cSoftCAM::Active(bool log)
+
+ void cSoftCAM::SetLogStatus(int CardNum, const cEcmInfo *ecm, bool on)
+ {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
++ cScDevice *dev=cScDevices::GetScDevice(CardNum);
+ if(dev && dev->Cam()) dev->Cam()->LogEcmStatus(ecm,on);
+ }
+
+ void cSoftCAM::AddHook(int CardNum, cLogHook *hook)
+ {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
++ cScDevice *dev=cScDevices::GetScDevice(CardNum);
+ if(dev && dev->Cam()) dev->Cam()->AddHook(hook);
+ }
+
+ bool cSoftCAM::TriggerHook(int CardNum, int id)
+ {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
++ cScDevice *dev=cScDevices::GetScDevice(CardNum);
+ return dev && dev->Cam() && dev->Cam()->TriggerHook(id);
+ }
+
+ void cSoftCAM::CaidsChanged(void)
+ {
+- for(int n=cDevice::NumDevices(); --n>=0;) {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
++ for(int n=cScDevices::numScDevices; --n>=0;) {
++ cScDevice *dev=cScDevices::scdevice[n];
+ if(dev) dev->CaidsChanged();
+ }
+ }
+
+ int cSoftCAM::FilterHandle(int CardNum)
+ {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(CardNum));
++ cScDevice *dev=cScDevices::GetScDevice(CardNum);
+ return dev ? dev->FilterHandle() : -1;
+ }
+
+@@ -1086,8 +1086,8 @@ void cScHousekeeper::Action(void)
+ while(Running()) {
+ if(++c==20) {
+ c=0;
+- for(int n=cDevice::NumDevices(); --n>=0;) {
+- cScDevice *dev=dynamic_cast<cScDevice *>(cDevice::GetDevice(n));
++ for(int n=cScDevices::numScDevices; --n>=0;) {
++ cScDevice *dev=cScDevices::scdevice[n];
+ if(dev && dev->Cam()) dev->Cam()->HouseKeeping();
+ }
+ }
diff --git a/patches/vdr-1.7.16-dynamite-subdevice.patch b/patches/vdr-1.7.16-dynamite-subdevice.patch
new file mode 100644
index 0000000..f0ee935
--- /dev/null
+++ b/patches/vdr-1.7.16-dynamite-subdevice.patch
@@ -0,0 +1,361 @@
+diff --git a/device.c b/device.c
+index 681049b..aaee92f 100644
+--- a/device.c
++++ b/device.c
+@@ -72,12 +72,18 @@ cDevice *cDevice::device[MAXDEVICES] = { NULL };
+ cDevice *cDevice::primaryDevice = NULL;
+ cDevice *cDevice::avoidDevice = NULL;
+ cList<cDeviceHook> cDevice::deviceHooks;
++cDevice *cDevice::nextParentDevice = NULL;
+
+-cDevice::cDevice(void)
++cDevice::cDevice(cDevice *ParentDevice)
+ :patPmtParser(true)
++,parentDevice(ParentDevice)
++,subDevice(NULL)
+ {
++ if (!ParentDevice)
++ parentDevice = nextParentDevice;
++ cDevice::nextParentDevice = NULL;
+ cardIndex = nextCardIndex++;
+- dsyslog("new device number %d", CardIndex() + 1);
++ dsyslog("new %sdevice number %d", parentDevice ? "sub-" : "", CardIndex() + 1);
+
+ SetDescription("receiver on device %d", CardIndex() + 1);
+
+@@ -108,10 +114,14 @@ cDevice::cDevice(void)
+ for (int i = 0; i < MAXRECEIVERS; i++)
+ receiver[i] = NULL;
+
+- if (numDevices < MAXDEVICES)
+- device[numDevices++] = this;
++ if (!parentDevice) {
++ if (numDevices < MAXDEVICES)
++ device[numDevices++] = this;
++ else
++ esyslog("ERROR: too many devices or \"dynamite\"-unpatched device creator!");
++ }
+ else
+- esyslog("ERROR: too many devices!");
++ parentDevice->subDevice = this;
+ }
+
+ cDevice::~cDevice()
+@@ -120,6 +130,8 @@ cDevice::~cDevice()
+ DetachAllReceivers();
+ delete liveSubtitle;
+ delete dvbSubtitleConverter;
++ if (parentDevice && (parentDevice->subDevice == this))
++ parentDevice->subDevice = NULL;
+ }
+
+ bool cDevice::WaitForAllDevicesReady(int Timeout)
+@@ -158,6 +170,8 @@ int cDevice::NextCardIndex(int n)
+
+ int cDevice::DeviceNumber(void) const
+ {
++ if (parentDevice)
++ return parentDevice->DeviceNumber();
+ for (int i = 0; i < numDevices; i++) {
+ if (device[i] == this)
+ return i;
+@@ -328,6 +342,10 @@ bool cDevice::HasCi(void)
+
+ void cDevice::SetCamSlot(cCamSlot *CamSlot)
+ {
++ if (parentDevice) {
++ parentDevice->SetCamSlot(CamSlot);
++ return;
++ }
+ camSlot = CamSlot;
+ }
+
+@@ -531,6 +549,10 @@ bool cDevice::SetPid(cPidHandle *Handle, int Type, bool On)
+
+ void cDevice::StartSectionHandler(void)
+ {
++ if (parentDevice) {
++ parentDevice->StartSectionHandler();
++ return;
++ }
+ if (!sectionHandler) {
+ sectionHandler = new cSectionHandler(this);
+ AttachFilter(eitFilter = new cEitFilter);
+@@ -542,6 +564,10 @@ void cDevice::StartSectionHandler(void)
+
+ void cDevice::StopSectionHandler(void)
+ {
++ if (parentDevice) {
++ parentDevice->StopSectionHandler();
++ return;
++ }
+ if (sectionHandler) {
+ delete nitFilter;
+ delete sdtFilter;
+@@ -568,12 +594,20 @@ void cDevice::CloseFilter(int Handle)
+
+ void cDevice::AttachFilter(cFilter *Filter)
+ {
++ if (parentDevice) {
++ parentDevice->AttachFilter(Filter);
++ return;
++ }
+ if (sectionHandler)
+ sectionHandler->Attach(Filter);
+ }
+
+ void cDevice::Detach(cFilter *Filter)
+ {
++ if (parentDevice) {
++ parentDevice->Detach(Filter);
++ return;
++ }
+ if (sectionHandler)
+ sectionHandler->Detach(Filter);
+ }
+@@ -1690,3 +1724,25 @@ uchar *cTSBuffer::Get(void)
+ }
+ return NULL;
+ }
++
++// --- cDynamicDeviceProbe -------------------------------------------------------
++
++cList<cDynamicDeviceProbe> DynamicDeviceProbes;
++
++cList<cDynamicDeviceProbe::cDynamicDeviceProbeItem> cDynamicDeviceProbe::commandQueue;
++
++void cDynamicDeviceProbe::QueueDynamicDeviceCommand(eDynamicDeviceProbeCommand Cmd, const char *DevPath)
++{
++ if (DevPath)
++ commandQueue.Add(new cDynamicDeviceProbeItem(Cmd, new cString(DevPath)));
++}
++
++cDynamicDeviceProbe::cDynamicDeviceProbe(void)
++{
++ DynamicDeviceProbes.Add(this);
++}
++
++cDynamicDeviceProbe::~cDynamicDeviceProbe()
++{
++ DynamicDeviceProbes.Del(this, false);
++}
+diff --git a/device.h b/device.h
+index cb3bc2c..0b6634b 100644
+--- a/device.h
++++ b/device.h
+@@ -163,7 +163,6 @@ private:
+ static int nextCardIndex;
+ int cardIndex;
+ protected:
+- cDevice(void);
+ virtual ~cDevice();
+ virtual bool Ready(void);
+ ///< Returns true if this device is ready. Devices with conditional
+@@ -191,8 +190,6 @@ protected:
+ ///< base class.
+ public:
+ bool IsPrimaryDevice(void) const { return this == primaryDevice; }
+- int CardIndex(void) const { return cardIndex; }
+- ///< Returns the card index of this device (0 ... MAXDEVICES - 1).
+ int DeviceNumber(void) const;
+ ///< Returns the number of this device (0 ... numDevices).
+ virtual bool HasDecoder(void) const;
+@@ -365,9 +362,6 @@ public:
+ ///< Returns true if this device has a Common Interface.
+ void SetCamSlot(cCamSlot *CamSlot);
+ ///< Sets the given CamSlot to be used with this device.
+- cCamSlot *CamSlot(void) const { return camSlot; }
+- ///< Returns the CAM slot that is currently used with this device,
+- ///< or NULL if no CAM slot is in use.
+
+ // Image Grab facilities
+
+@@ -524,9 +518,6 @@ private:
+ cTsToPes tsToPesSubtitle;
+ bool isPlayingVideo;
+ protected:
+- const cPatPmtParser *PatPmtParser(void) const { return &patPmtParser; }
+- ///< Returns a pointer to the patPmtParser, so that a derived device
+- ///< can use the stream information from it.
+ virtual bool CanReplay(void) const;
+ ///< Returns true if this device can currently start a replay session.
+ virtual bool SetPlayMode(ePlayMode PlayMode);
+@@ -712,6 +703,30 @@ public:
+ ///< Detaches all receivers from this device for this pid.
+ void DetachAllReceivers(void);
+ ///< Detaches all receivers from this device.
++
++// --- dynamite subdevice patch start ---
++ friend class cDynamicDevice;
++private:
++ static cDevice *nextParentDevice;
++ ///< Holds the parent device for the next subdevice
++ ///< so the dynamite-plugin can work with unpatched plugins
++protected:
++ cDevice *parentDevice;
++ cDevice *subDevice;
++ cDevice(cDevice *ParentDevice = NULL);
++ const cPatPmtParser *PatPmtParser(void) const { if (parentDevice) return parentDevice->PatPmtParser(); return &patPmtParser; }
++ ///< Returns a pointer to the patPmtParser, so that a derived device
++ ///< can use the stream information from it.
++public:
++ int CardIndex(void) const { if (parentDevice) return parentDevice->cardIndex; return cardIndex; }
++ ///< Returns the card index of this device (0 ... MAXDEVICES - 1).
++ cCamSlot *CamSlot(void) const { if (parentDevice) return parentDevice->CamSlot(); return camSlot; }
++ ///< Returns the CAM slot that is currently used with this device,
++ ///< or NULL if no CAM slot is in use.
++ bool IsSubDevice(void) const { return (parentDevice != NULL); }
++ bool HasSubDevice(void) const { return (subDevice != NULL); }
++ cDevice *SubDevice(void) const { return subDevice; }
++ // --- dynamite subdevice patch end ---
+ };
+
+ /// Derived cDevice classes that can receive channels will have to provide
+@@ -735,4 +750,47 @@ public:
+ uchar *Get(void);
+ };
+
++/// A plugin that want to create devices handled by the dynamite-plugin needs to create
++/// a cDynamicDeviceProbe derived object on the heap in order to have its Probe()
++/// function called, where it can actually create the appropriate device.
++/// The cDynamicDeviceProbe object must be created in the plugin's constructor,
++/// and deleted in its destructor.
++/// The "DevPath" hasn't to be a physical device or a path in the filesystem.
++/// It can be any string a plugin may react on.
++
++#define __DYNAMIC_DEVICE_PROBE
++
++enum eDynamicDeviceProbeCommand { ddpcAttach, ddpcDetach };
++
++class cDynamicDeviceProbe : public cListObject {
++ friend class cDynamicDevice;
++private:
++ class cDynamicDeviceProbeItem : public cListObject {
++ public:
++ eDynamicDeviceProbeCommand cmd;
++ cString *devpath;
++ cDynamicDeviceProbeItem(eDynamicDeviceProbeCommand Cmd, cString *DevPath):cmd(Cmd),devpath(DevPath) {}
++ virtual ~cDynamicDeviceProbeItem() { if (devpath) delete devpath; }
++ };
++ static cList<cDynamicDeviceProbeItem> commandQueue;
++ ///< A list where all attach/detach commands are queued
++ ///< so they can be processed in the MainThreadHook of
++ ///< the dynamite plugin.
++public:
++ static void QueueDynamicDeviceCommand(eDynamicDeviceProbeCommand Cmd, const char *DevPath);
++ ///< Plugins which support cDynamicDeviceProbe must use this function
++ ///< to queue the devices they normally create in their Initialize method.
++ ///< These devices are created as subdevices in the Start-method of the dynamite-plugin.
++ cDynamicDeviceProbe(void);
++ virtual ~cDynamicDeviceProbe();
++ virtual cDevice *Attach(cDevice *ParentDevice, const char *DevPath) = 0;
++ ///< Probes for a device at the given device-path like /dev/dvb/adapter0/frontend0
++ ///< or /dev/video0 etc. and creates the appropriate
++ ///< object derived from cDevice if applicable.
++ ///< Returns the device that has been created or NULL if not.
++ ///< The dynamite-plugin will delete the device if it is detached.
++ };
++
++extern cList<cDynamicDeviceProbe> DynamicDeviceProbes;
++
+ #endif //__DEVICE_H
+diff --git a/dvbci.c b/dvbci.c
+index 5289bbd..ea54bdb 100644
+--- a/dvbci.c
++++ b/dvbci.c
+@@ -41,6 +41,8 @@ cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd)
+ cDvbCiAdapter::~cDvbCiAdapter()
+ {
+ Cancel(3);
++ if (device->IsSubDevice() || device->HasSubDevice())
++ close(fd);
+ }
+
+ int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength)
+diff --git a/dvbdevice.c b/dvbdevice.c
+index f32b350..df2e679 100644
+--- a/dvbdevice.c
++++ b/dvbdevice.c
+@@ -259,6 +259,7 @@ private:
+ int device;
+ int fd_frontend;
+ int adapter, frontend;
++ cDvbDevice *dvbdevice;
+ int tuneTimeout;
+ int lockTimeout;
+ time_t lastTimeoutReport;
+@@ -273,7 +274,7 @@ private:
+ bool SetFrontend(void);
+ virtual void Action(void);
+ public:
+- cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType);
++ cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType, cDvbDevice *Dvbdevice);
+ virtual ~cDvbTuner();
+ const cChannel *GetTransponder(void) const { return &channel; }
+ bool IsTunedTo(const cChannel *Channel) const;
+@@ -281,13 +282,14 @@ public:
+ bool Locked(int TimeoutMs = 0);
+ };
+
+-cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType)
++cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType, cDvbDevice *Dvbdevice)
+ {
+ device = Device;
+ fd_frontend = Fd_Frontend;
+ adapter = Adapter;
+ frontend = Frontend;
+ frontendType = FrontendType;
++ dvbdevice = Dvbdevice;
+ tuneTimeout = 0;
+ lockTimeout = 0;
+ lastTimeoutReport = 0;
+@@ -305,6 +307,8 @@ cDvbTuner::~cDvbTuner()
+ newSet.Broadcast();
+ locked.Broadcast();
+ Cancel(3);
++ if (dvbdevice && dvbdevice->IsSubDevice())
++ close(fd_frontend);
+ }
+
+ bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
+@@ -661,7 +665,8 @@ const char *DeliverySystems[] = {
+ NULL
+ };
+
+-cDvbDevice::cDvbDevice(int Adapter, int Frontend)
++cDvbDevice::cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice)
++:cDevice(ParentDevice)
+ {
+ adapter = Adapter;
+ frontend = Frontend;
+@@ -678,7 +683,7 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend)
+
+ fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
+ if (fd_ca >= 0)
+- ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca);
++ ciAdapter = cDvbCiAdapter::CreateCiAdapter(parentDevice ? parentDevice : this, fd_ca);
+
+ // The DVR device (will be opened and closed as needed):
+
+@@ -718,7 +723,7 @@ cDvbDevice::cDvbDevice(int Adapter, int Frontend)
+ else
+ p = (char *)"unknown modulations";
+ isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], p, frontendInfo.name);
+- dvbTuner = new cDvbTuner(CardIndex() + 1, fd_frontend, adapter, frontend, frontendType);
++ dvbTuner = new cDvbTuner(CardIndex() + 1, fd_frontend, adapter, frontend, frontendType, this);
+ }
+ }
+ else
+diff --git a/dvbdevice.h b/dvbdevice.h
+index ff606fd..0ac3a24 100644
+--- a/dvbdevice.h
++++ b/dvbdevice.h
+@@ -123,7 +123,7 @@ private:
+ fe_delivery_system frontendType;
+ int fd_dvr, fd_ca;
+ public:
+- cDvbDevice(int Adapter, int Frontend);
++ cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice = NULL);
+ virtual ~cDvbDevice();
+ virtual bool Ready(void);
+