diff options
| author | Lars Hanisch <dvb@flensrocker.de> | 2015-06-03 17:09:35 +0200 | 
|---|---|---|
| committer | Lars Hanisch <dvb@flensrocker.de> | 2015-06-03 17:09:35 +0200 | 
| commit | 5c83dd552a867e3fec0d166527d6545c0253cd42 (patch) | |
| tree | 8f3922317401749b35e687b38be6467df0806eb8 | |
| parent | 6d80369a7f30e7f294493bfc53451ffb08a6a472 (diff) | |
| download | vdr-plugin-dynamite-5c83dd552a867e3fec0d166527d6545c0253cd42.tar.gz vdr-plugin-dynamite-5c83dd552a867e3fec0d166527d6545c0253cd42.tar.bz2 | |
add patch for vdr 2.2.0
| -rw-r--r-- | patches/vdr-2.2.0-dynamite.diff | 803 | 
1 files changed, 803 insertions, 0 deletions
| diff --git a/patches/vdr-2.2.0-dynamite.diff b/patches/vdr-2.2.0-dynamite.diff new file mode 100644 index 0000000..bfd1783 --- /dev/null +++ b/patches/vdr-2.2.0-dynamite.diff @@ -0,0 +1,803 @@ +diff --git a/ci.h b/ci.h +index 5a4dc98..f5b2fbe 100644 +--- a/ci.h ++++ b/ci.h +@@ -116,6 +116,8 @@ public: +   cCiAdapter(void); +   virtual ~cCiAdapter(); +        ///< The derived class must call Cancel(3) in its destructor. ++  virtual bool SetIdle(bool Idle, bool TestOnly) { return false; } ++  virtual bool IsIdle(void) const { return false; } +   }; +  + class cTPDU; +diff --git a/device.c b/device.c +index 14ab07d..e892212 100644 +--- a/device.c ++++ b/device.c +@@ -70,12 +70,22 @@ int cDevice::currentChannel = 1; + cDevice *cDevice::device[MAXDEVICES] = { NULL }; + cDevice *cDevice::primaryDevice = NULL; + cList<cDeviceHook> cDevice::deviceHooks; ++cDevice *cDevice::nextParentDevice = NULL; +  +-cDevice::cDevice(void) ++cDevice::cDevice(cDevice *ParentDevice) + :patPmtParser(true) +-{ +-  cardIndex = nextCardIndex++; +-  dsyslog("new device number %d", CardIndex() + 1); ++,isIdle(false) ++,parentDevice(ParentDevice) ++,subDevice(NULL) ++{ ++  if (!ParentDevice) ++     parentDevice = nextParentDevice; ++  cDevice::nextParentDevice = NULL; ++  if (parentDevice) ++     cardIndex = parentDevice->cardIndex; ++  else ++     cardIndex = nextCardIndex++; ++  dsyslog("new %sdevice number %d", parentDevice ? "sub-" : "", CardIndex() + 1); +  +   SetDescription("device %d receiver", CardIndex() + 1); +  +@@ -107,10 +117,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() +@@ -121,6 +135,29 @@ cDevice::~cDevice() +   delete dvbSubtitleConverter; +   if (this == primaryDevice) +      primaryDevice = NULL; ++  if (parentDevice && (parentDevice->subDevice == this)) ++     parentDevice->subDevice = NULL; ++} ++ ++bool cDevice::SetIdle(bool Idle) ++{ ++  if (parentDevice) ++     return parentDevice->SetIdle(Idle); ++  if (isIdle == Idle) ++     return true; ++  if (Receiving(false)) ++     return false; ++  if (Idle) { ++     Detach(player); ++     DetachAllReceivers(); ++     } ++  if (!SetIdleDevice(Idle, true)) ++     return false; ++  isIdle = Idle; ++  if (SetIdleDevice(Idle, false)) ++     return true; ++  isIdle = !Idle; ++  return false; + } +  + bool cDevice::WaitForAllDevicesReady(int Timeout) +@@ -159,6 +196,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; +@@ -359,6 +398,8 @@ bool cDevice::HasCi(void) +  + void cDevice::SetCamSlot(cCamSlot *CamSlot) + { ++  if (parentDevice) ++     return parentDevice->SetCamSlot(CamSlot); +   LOCK_THREAD; +   camSlot = CamSlot; + } +@@ -566,6 +607,10 @@ void cDevice::DelLivePids(void) +  + void cDevice::StartSectionHandler(void) + { ++  if (parentDevice) { ++     parentDevice->StartSectionHandler(); ++     return; ++     } +   if (!sectionHandler) { +      sectionHandler = new cSectionHandler(this); +      AttachFilter(eitFilter = new cEitFilter); +@@ -577,6 +622,10 @@ void cDevice::StartSectionHandler(void) +  + void cDevice::StopSectionHandler(void) + { ++  if (parentDevice) { ++     parentDevice->StopSectionHandler(); ++     return; ++     } +   if (sectionHandler) { +      delete nitFilter; +      delete sdtFilter; +@@ -608,12 +657,17 @@ void cDevice::CloseFilter(int Handle) +  + void cDevice::AttachFilter(cFilter *Filter) + { ++  if (parentDevice) ++     return parentDevice->AttachFilter(Filter); ++  SetIdle(false); +   if (sectionHandler) +      sectionHandler->Attach(Filter); + } +  + void cDevice::Detach(cFilter *Filter) + { ++  if (parentDevice) ++     return parentDevice->Detach(Filter); +   if (sectionHandler) +      sectionHandler->Detach(Filter); + } +@@ -783,6 +837,7 @@ eSetChannelResult cDevice::SetChannel(const cChannel *Channel, bool LiveView) +         sectionHandler->SetStatus(false); +         sectionHandler->SetChannel(NULL); +         } ++     SetIdle(false); +      // Tell the camSlot about the channel switch and add all PIDs of this +      // channel to it, for possible later decryption: +      if (camSlot) +@@ -830,19 +885,27 @@ void cDevice::ForceTransferMode(void) + { +   if (!cTransferControl::ReceiverDevice()) { +      cChannel *Channel = Channels.GetByNumber(CurrentChannel()); +-     if (Channel) ++     if (Channel) { ++        SetIdle(false); +         SetChannelDevice(Channel, false); // this implicitly starts Transfer Mode ++        } +      } + } +  + int cDevice::Occupied(void) const + { ++  if (parentDevice) ++     return parentDevice->Occupied(); +   int Seconds = occupiedTimeout - time(NULL); +   return Seconds > 0 ? Seconds : 0; + } +  + void cDevice::SetOccupied(int Seconds) + { ++  if (parentDevice) { ++     parentDevice->SetOccupied(Seconds); ++     return; ++     } +   if (Seconds >= 0) +      occupiedTimeout = time(NULL) + min(Seconds, MAXOCCUPIEDTIMEOUT); + } +@@ -1225,7 +1288,10 @@ bool cDevice::Transferring(void) const +  + bool cDevice::AttachPlayer(cPlayer *Player) + { ++  if (parentDevice) ++     return parentDevice->AttachPlayer(Player); +   if (CanReplay()) { ++     SetIdle(false); +      if (player) +         Detach(player); +      DELETENULL(liveSubtitle); +@@ -1244,6 +1310,8 @@ bool cDevice::AttachPlayer(cPlayer *Player) +  + void cDevice::Detach(cPlayer *Player) + { ++  if (parentDevice) ++     return parentDevice->Detach(Player); +   if (Player && player == Player) { +      cPlayer *p = player; +      player = NULL; // avoids recursive calls to Detach() +@@ -1263,6 +1331,8 @@ void cDevice::Detach(cPlayer *Player) +  + void cDevice::StopReplay(void) + { ++  if (parentDevice) ++     return parentDevice->StopReplay(); +   if (player) { +      Detach(player); +      if (IsPrimaryDevice()) +@@ -1543,6 +1613,8 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) +  + int cDevice::Priority(void) const + { ++  if (parentDevice) ++     return parentDevice->Priority(); +   int priority = IDLEPRIORITY; +   if (IsPrimaryDevice() && !Replaying() && HasProgramme()) +      priority = TRANSFERPRIORITY; // we use the same value here, no matter whether it's actual Transfer Mode or real live viewing +@@ -1561,6 +1633,8 @@ bool cDevice::Ready(void) +  + bool cDevice::Receiving(bool Dummy) const + { ++  if (parentDevice) ++     return parentDevice->Receiving(Dummy); +   cMutexLock MutexLock(&mutexReceiver); +   for (int i = 0; i < MAXRECEIVERS; i++) { +       if (receiver[i]) +@@ -1642,10 +1716,13 @@ bool cDevice::GetTSPacket(uchar *&Data) +  + bool cDevice::AttachReceiver(cReceiver *Receiver) + { ++  if (parentDevice) ++     return parentDevice->AttachReceiver(Receiver); +   if (!Receiver) +      return false; +   if (Receiver->device == this) +      return true; ++  SetIdle(false); + // activate the following line if you need it - actually the driver should be fixed! + //#define WAIT_FOR_TUNER_LOCK + #ifdef WAIT_FOR_TUNER_LOCK +@@ -1684,6 +1761,8 @@ bool cDevice::AttachReceiver(cReceiver *Receiver) +  + void cDevice::Detach(cReceiver *Receiver) + { ++  if (parentDevice) ++     return parentDevice->Detach(Receiver); +   if (!Receiver || Receiver->device != this) +      return; +   bool receiversLeft = false; +@@ -1714,6 +1793,8 @@ void cDevice::Detach(cReceiver *Receiver) +  + void cDevice::DetachAll(int Pid) + { ++  if (parentDevice) ++     return parentDevice->DetachAll(Pid); +   if (Pid) { +      cMutexLock MutexLock(&mutexReceiver); +      for (int i = 0; i < MAXRECEIVERS; i++) { +@@ -1806,3 +1887,25 @@ void cTSBuffer::Skip(int Count) +   ringBuffer->Del(Count); +   delivered = false; + } ++ ++// --- 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 b06d977..a1c29a3 100644 +--- a/device.h ++++ b/device.h +@@ -174,7 +174,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 +@@ -201,9 +200,6 @@ protected: +          ///< A derived class must call the MakePrimaryDevice() function of its +          ///< base class. + public: +-  bool IsPrimaryDevice(void) const { return this == primaryDevice && HasDecoder(); } +-  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 - 1). +   virtual cString DeviceType(void) const; +@@ -433,9 +429,6 @@ public: +          ///< shall check whether the channel can be decrypted. +   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 +  +@@ -604,9 +597,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); +@@ -821,6 +811,38 @@ public: +        ///< Detaches all receivers from this device for this pid. +   virtual 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 ++  bool isIdle; ++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: ++  bool IsPrimaryDevice(void) const { if (parentDevice) return parentDevice->IsPrimaryDevice(); return this == primaryDevice && HasDecoder(); } ++  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; } ++  bool IsIdle(void) const { if (parentDevice) return parentDevice->IsIdle(); return isIdle; } ++  bool SetIdle(bool Idle); ++  virtual bool SetIdleDevice(bool Idle, bool TestOnly) { return false; } ++         ///< Called by SetIdle ++         ///< if TestOnly, don't do anything, just return, if the device ++         ///< can be set to the new idle state ++  // --- dynamite subdevice patch end --- +   }; +  + /// Derived cDevice classes that can receive channels will have to provide +@@ -857,4 +879,47 @@ public: +      ///< to Get(). +   }; +  ++/// 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, ddpcService }; ++ ++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 fa65f0f..10a5819 100644 +--- a/dvbci.c ++++ b/dvbci.c +@@ -10,15 +10,18 @@ + #include "dvbci.h" + #include <linux/dvb/ca.h> + #include <sys/ioctl.h> +-#include "device.h" ++#include "dvbdevice.h" +  + // --- cDvbCiAdapter --------------------------------------------------------- +  +-cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd) ++cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd, int Adapter, int Frontend) + { +   device = Device; +   SetDescription("device %d CI adapter", device->DeviceNumber()); +   fd = Fd; ++  adapter = Adapter; ++  frontend = Frontend; ++  idle = false; +   ca_caps_t Caps; +   if (ioctl(fd, CA_GET_CAP, &Caps) == 0) { +      if ((Caps.slot_type & CA_CI_LINK) != 0) { +@@ -41,10 +44,44 @@ cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd) + cDvbCiAdapter::~cDvbCiAdapter() + { +   Cancel(3); ++  if (device->IsSubDevice() || device->HasSubDevice()) ++     CloseCa(); ++} ++ ++bool cDvbCiAdapter::OpenCa(void) ++{ ++  if (fd >= 0) ++     return true; ++  fd = cDvbDevice::DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR); ++  return (fd >= 0); ++} ++ ++void cDvbCiAdapter::CloseCa(void) ++{ ++  if (fd < 0) ++     return; ++  close(fd); ++  fd = -1; ++} ++ ++bool cDvbCiAdapter::SetIdle(bool Idle, bool TestOnly) ++{ ++  if ((adapter < 0) || (frontend < 0)) ++     return false; ++  if (TestOnly || (idle == Idle)) ++     return true; ++  if (Idle) ++     CloseCa(); ++  else ++     OpenCa(); ++  idle = Idle; ++  return true; + } +  + int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength) + { ++  if (idle || (fd < 0)) ++     return 0; +   if (Buffer && MaxLength > 0) { +      struct pollfd pfd[1]; +      pfd[0].fd = fd; +@@ -61,6 +98,8 @@ int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength) +  + void cDvbCiAdapter::Write(const uint8_t *Buffer, int Length) + { ++  if (idle || (fd < 0)) ++     return; +   if (Buffer && Length > 0) { +      if (safe_write(fd, Buffer, Length) != Length) +         esyslog("ERROR: can't write to CI adapter on device %d: %m", device->DeviceNumber()); +@@ -69,6 +108,8 @@ void cDvbCiAdapter::Write(const uint8_t *Buffer, int Length) +  + bool cDvbCiAdapter::Reset(int Slot) + { ++  if (idle || (fd < 0)) ++     return false; +   if (ioctl(fd, CA_RESET, 1 << Slot) != -1) +      return true; +   else +@@ -78,6 +119,8 @@ bool cDvbCiAdapter::Reset(int Slot) +  + eModuleStatus cDvbCiAdapter::ModuleStatus(int Slot) + { ++  if (idle || (fd < 0)) ++     return msNone; +   ca_slot_info_t sinfo; +   sinfo.num = Slot; +   if (ioctl(fd, CA_GET_SLOT_INFO, &sinfo) != -1) { +@@ -99,10 +142,10 @@ bool cDvbCiAdapter::Assign(cDevice *Device, bool Query) +   return true; + } +  +-cDvbCiAdapter *cDvbCiAdapter::CreateCiAdapter(cDevice *Device, int Fd) ++cDvbCiAdapter *cDvbCiAdapter::CreateCiAdapter(cDevice *Device, int Fd, int Adapter, int Frontend) + { +   // TODO check whether a CI is actually present? +   if (Device) +-     return new cDvbCiAdapter(Device, Fd); ++     return new cDvbCiAdapter(Device, Fd, Adapter, Frontend); +   return NULL; + } +diff --git a/dvbci.h b/dvbci.h +index f74703c..eaf9a34 100644 +--- a/dvbci.h ++++ b/dvbci.h +@@ -16,16 +16,24 @@ class cDvbCiAdapter : public cCiAdapter { + private: +   cDevice *device; +   int fd; ++  int adapter; ++  int frontend; ++  bool idle; ++ ++  bool OpenCa(void); ++  void CloseCa(void); + protected: +   virtual int Read(uint8_t *Buffer, int MaxLength); +   virtual void Write(const uint8_t *Buffer, int Length); +   virtual bool Reset(int Slot); +   virtual eModuleStatus ModuleStatus(int Slot); +   virtual bool Assign(cDevice *Device, bool Query = false); +-  cDvbCiAdapter(cDevice *Device, int Fd); ++  cDvbCiAdapter(cDevice *Device, int Fd, int Adapter = -1, int Frontend = -1); + public: +   virtual ~cDvbCiAdapter(); +-  static cDvbCiAdapter *CreateCiAdapter(cDevice *Device, int Fd); ++  virtual bool SetIdle(bool Idle, bool TestOnly); ++  virtual bool IsIdle(void) const { return idle; } ++  static cDvbCiAdapter *CreateCiAdapter(cDevice *Device, int Fd, int Adapter = -1, int Frontend = -1); +   }; +  + #endif //__DVBCI_H +diff --git a/dvbdevice.c b/dvbdevice.c +index 9321f16..f02baab 100644 +--- a/dvbdevice.c ++++ b/dvbdevice.c +@@ -303,7 +303,7 @@ private: +   enum eTunerStatus { tsIdle, tsSet, tsPositioning, tsTuned, tsLocked }; +   int frontendType; +   const cDvbDevice *device; +-  int fd_frontend; ++  mutable int fd_frontend; +   int adapter, frontend; +   uint32_t subsystemId; +   int tuneTimeout; +@@ -317,7 +317,7 @@ private: +   const cScr *scr; +   bool lnbPowerTurnedOn; +   eTunerStatus tunerStatus; +-  cMutex mutex; ++  mutable cMutex mutex; +   cCondVar locked; +   cCondVar newSet; +   cDvbTuner *bondedTuner; +@@ -333,6 +333,10 @@ private: +   void ResetToneAndVoltage(void); +   bool SetFrontend(void); +   virtual void Action(void); ++ ++  mutable bool isIdle; ++  bool OpenFrontend(void) const; ++  bool CloseFrontend(void); + public: +   cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int Frontend); +   virtual ~cDvbTuner(); +@@ -348,6 +352,8 @@ public: +   const cPositioner *Positioner(void) const { return positioner; } +   int GetSignalStrength(void) const; +   int GetSignalQuality(void) const; ++  bool SetIdle(bool Idle); ++  bool IsIdle(void) const { return isIdle; } +   }; +  + cMutex cDvbTuner::bondMutex; +@@ -372,6 +378,7 @@ cDvbTuner::cDvbTuner(const cDvbDevice *Device, int Fd_Frontend, int Adapter, int +   tunerStatus = tsIdle; +   bondedTuner = NULL; +   bondedMaster = false; ++  isIdle = false; +   SetDescription("frontend %d/%d tuner", adapter, frontend); +   Start(); + } +@@ -389,6 +396,8 @@ cDvbTuner::~cDvbTuner() +      ExecuteDiseqc(lastDiseqc, &Frequency); +      } +   */ ++  if (device && device->IsSubDevice()) ++     CloseFrontend(); + } +  + bool cDvbTuner::Bond(cDvbTuner *Tuner) +@@ -534,6 +543,8 @@ bool cDvbTuner::Locked(int TimeoutMs) +  + void cDvbTuner::ClearEventQueue(void) const + { ++  if (!OpenFrontend()) ++     return; +   cPoller Poller(fd_frontend); +   if (Poller.Poll(TUNER_POLL_TIMEOUT)) { +      dvb_frontend_event Event; +@@ -777,6 +788,8 @@ static int GetRequiredDeliverySystem(const cChannel *Channel, const cDvbTranspon +  + bool cDvbTuner::SetFrontend(void) + { ++  if (!OpenFrontend()) ++     return false; + #define MAXFRONTENDCMDS 16 + #define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\ +                        Frontend[CmdSeq.num].u.data = (d);\ +@@ -929,9 +942,11 @@ void cDvbTuner::Action(void) +   bool LostLock = false; +   fe_status_t Status = (fe_status_t)0; +   while (Running()) { +-        fe_status_t NewStatus; +-        if (GetFrontendStatus(NewStatus)) +-           Status = NewStatus; ++        if (!isIdle) { ++           fe_status_t NewStatus; ++           if (GetFrontendStatus(NewStatus)) ++              Status = NewStatus; ++           } +         cMutexLock MutexLock(&mutex); +         int WaitTime = 1000; +         switch (tunerStatus) { +@@ -1001,6 +1016,40 @@ void cDvbTuner::Action(void) +         } + } +  ++bool cDvbTuner::SetIdle(bool Idle) ++{ ++  if (isIdle == Idle) ++     return true; ++  isIdle = Idle; ++  if (Idle) ++     return CloseFrontend(); ++  return OpenFrontend(); ++} ++ ++bool cDvbTuner::OpenFrontend(void) const ++{ ++  if (fd_frontend >= 0) ++     return true; ++  cMutexLock MutexLock(&mutex); ++  fd_frontend = cDvbDevice::DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK); ++  if (fd_frontend < 0) ++     return false; ++  isIdle = false; ++  return true; ++} ++ ++bool cDvbTuner::CloseFrontend(void) ++{ ++  if (fd_frontend < 0) ++     return true; ++  cMutexLock MutexLock(&mutex); ++  tunerStatus = tsIdle; ++  newSet.Broadcast(); ++  close(fd_frontend); ++  fd_frontend = -1; ++  return true; ++} ++ + // --- cDvbSourceParam ------------------------------------------------------- +  + class cDvbSourceParam : public cSourceParam { +@@ -1089,7 +1138,8 @@ const char *DeliverySystemNames[] = { +   NULL +   }; +  +-cDvbDevice::cDvbDevice(int Adapter, int Frontend) ++cDvbDevice::cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice) ++:cDevice(ParentDevice) + { +   adapter = Adapter; +   frontend = Frontend; +@@ -1109,7 +1159,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, adapter, frontend); +  +   // The DVR device (will be opened and closed as needed): +  +@@ -1349,7 +1399,11 @@ bool cDvbDevice::BondDevices(const char *Bondings) +          if (d >= 0) { +             int ErrorDevice = 0; +             if (cDevice *Device1 = cDevice::GetDevice(i)) { ++               if (Device1->HasSubDevice()) ++                  Device1 = Device1->SubDevice(); +                if (cDevice *Device2 = cDevice::GetDevice(d)) { ++                  if (Device2->HasSubDevice()) ++                     Device2 = Device2->SubDevice(); +                   if (cDvbDevice *DvbDevice1 = dynamic_cast<cDvbDevice *>(Device1)) { +                      if (cDvbDevice *DvbDevice2 = dynamic_cast<cDvbDevice *>(Device2)) { +                         if (!DvbDevice1->Bond(DvbDevice2)) +@@ -1383,7 +1437,10 @@ bool cDvbDevice::BondDevices(const char *Bondings) + void cDvbDevice::UnBondDevices(void) + { +   for (int i = 0; i < cDevice::NumDevices(); i++) { +-      if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(cDevice::GetDevice(i))) ++      cDevice *dev = cDevice::GetDevice(i); ++      if (dev && dev->HasSubDevice()) ++         dev = dev->SubDevice(); ++      if (cDvbDevice *d = dynamic_cast<cDvbDevice *>(dev)) +          d->UnBond(); +       } + } +@@ -1437,6 +1494,26 @@ bool cDvbDevice::BondingOk(const cChannel *Channel, bool ConsiderOccupied) const +   return true; + } +  ++bool cDvbDevice::SetIdleDevice(bool Idle, bool TestOnly) ++{ ++  if (TestOnly) { ++     if (ciAdapter) ++        return ciAdapter->SetIdle(Idle, true); ++     return true; ++     } ++  if (!dvbTuner->SetIdle(Idle)) ++     return false; ++  if (ciAdapter && !ciAdapter->SetIdle(Idle, false)) { ++     dvbTuner->SetIdle(!Idle); ++     return false; ++     } ++  if (Idle) ++     StopSectionHandler(); ++  else ++     StartSectionHandler(); ++  return true; ++} ++ + bool cDvbDevice::HasCi(void) + { +   return ciAdapter; +@@ -1606,7 +1683,7 @@ bool cDvbDevice::ProvidesChannel(const cChannel *Channel, int Priority, bool *Ne +  + bool cDvbDevice::ProvidesEIT(void) const + { +-  return dvbTuner != NULL; ++  return !IsIdle() && (dvbTuner != NULL) && !dvbTuner->IsIdle() && ((ciAdapter == NULL) || !ciAdapter->IsIdle()); + } +  + int cDvbDevice::NumProvidedSystems(void) const +diff --git a/dvbdevice.h b/dvbdevice.h +index 0a148ce..922703e 100644 +--- a/dvbdevice.h ++++ b/dvbdevice.h +@@ -165,7 +165,7 @@ class cDvbTuner; + /// The cDvbDevice implements a DVB device which can be accessed through the Linux DVB driver API. +  + class cDvbDevice : public cDevice { +-protected: ++public: +   static cString DvbName(const char *Name, int Adapter, int Frontend); +   static int DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError = false); + private: +@@ -191,12 +191,14 @@ private: +   mutable bool needsDetachBondedReceivers; +   bool QueryDeliverySystems(int fd_frontend); + public: +-  cDvbDevice(int Adapter, int Frontend); ++  cDvbDevice(int Adapter, int Frontend, cDevice *ParentDevice = NULL); +   virtual ~cDvbDevice(); +   int Adapter(void) const { return adapter; } +   int Frontend(void) const { return frontend; } +   virtual cString DeviceType(void) const; +   virtual cString DeviceName(void) const; ++  virtual bool SetIdleDevice(bool Idle, bool TestOnly); ++ +   static bool BondDevices(const char *Bondings); +        ///< Bonds the devices as defined in the given Bondings string. +        ///< A bonding is a sequence of device numbers (starting at 1), | 
