diff --git a/ci.h b/ci.h index c31dccf..daa18f6 100644 --- a/ci.h +++ b/ci.h @@ -115,6 +115,8 @@ public: ///< The derived class must call Cancel(3) in its destructor. virtual bool Ready(void); ///< Returns 'true' if all present CAMs in this adapter are ready. + 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 60340c0..ba2a014 100644 --- a/device.c +++ b/device.c @@ -72,12 +72,22 @@ cDevice *cDevice::device[MAXDEVICES] = { NULL }; cDevice *cDevice::primaryDevice = NULL; cDevice *cDevice::avoidDevice = NULL; cList 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("receiver on device %d", CardIndex() + 1); @@ -108,10 +118,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 +134,29 @@ cDevice::~cDevice() DetachAllReceivers(); delete liveSubtitle; delete dvbSubtitleConverter; + 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) @@ -158,6 +195,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 +367,8 @@ bool cDevice::HasCi(void) void cDevice::SetCamSlot(cCamSlot *CamSlot) { + if (parentDevice) + return parentDevice->SetCamSlot(CamSlot); camSlot = CamSlot; } @@ -531,6 +572,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 +587,10 @@ void cDevice::StartSectionHandler(void) void cDevice::StopSectionHandler(void) { + if (parentDevice) { + parentDevice->StopSectionHandler(); + return; + } if (sectionHandler) { delete nitFilter; delete sdtFilter; @@ -568,12 +617,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); } @@ -720,6 +774,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) @@ -766,8 +821,10 @@ 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 + } } } @@ -1138,7 +1195,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); @@ -1157,6 +1217,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() @@ -1176,6 +1238,8 @@ void cDevice::Detach(cPlayer *Player) void cDevice::StopReplay(void) { + if (parentDevice) + return parentDevice->StopReplay(); if (player) { Detach(player); if (IsPrimaryDevice()) @@ -1458,6 +1522,8 @@ int cDevice::PlayTs(const uchar *Data, int Length, bool VideoOnly) int cDevice::Priority(void) const { + if (parentDevice) + return parentDevice->Priority(); int priority = IsPrimaryDevice() ? Setup.PrimaryLimit - 1 : DEFAULTPRIORITY; for (int i = 0; i < MAXRECEIVERS; i++) { if (receiver[i]) @@ -1473,6 +1539,8 @@ bool cDevice::Ready(void) bool cDevice::Receiving(bool CheckAny) const { + if (parentDevice) + return parentDevice->Receiving(CheckAny); for (int i = 0; i < MAXRECEIVERS; i++) { if (receiver[i] && (CheckAny || receiver[i]->priority >= 0)) // cReceiver with priority < 0 doesn't count return true; @@ -1552,10 +1620,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 @@ -1594,6 +1665,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; @@ -1619,6 +1692,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++) { @@ -1631,6 +1706,8 @@ void cDevice::DetachAll(int Pid) void cDevice::DetachAllReceivers(void) { + if (parentDevice) + return parentDevice->DetachAllReceivers(); cMutexLock MutexLock(&mutexReceiver); for (int i = 0; i < MAXRECEIVERS; i++) Detach(receiver[i]); @@ -1702,3 +1779,25 @@ uchar *cTSBuffer::Get(void) } return NULL; } + +// --- cDynamicDeviceProbe ------------------------------------------------------- + +cList DynamicDeviceProbes; + +cList 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 1598af2..7340392 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 @@ -190,9 +189,6 @@ protected: ///< A derived class must call the MakePrimaryDevice() function of its ///< 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 +361,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 +517,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 +702,39 @@ 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 + 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; } + 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 + virtual bool CanScanForEPG(void) const { return !IsIdle(); } + // --- dynamite subdevice patch end --- }; /// Derived cDevice classes that can receive channels will have to provide @@ -735,4 +758,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, 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 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 DynamicDeviceProbes; + #endif //__DEVICE_H diff --git a/dvbci.c b/dvbci.c index 5289bbd..fea3a83 100644 --- a/dvbci.c +++ b/dvbci.c @@ -10,15 +10,18 @@ #include "dvbci.h" #include #include -#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("CI adapter on device %d", 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 adbe40d..6d117b2 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 f32b350..755d9e0 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; @@ -269,30 +270,37 @@ private: cMutex mutex; cCondVar locked; cCondVar newSet; + bool isIdle; + bool OpenFrontend(void); + bool CloseFrontend(void); bool GetFrontendStatus(fe_status_t &Status, int TimeoutMs = 0); 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; void Set(const cChannel *Channel); bool Locked(int TimeoutMs = 0); + bool SetIdle(bool Idle); + bool IsIdle(void) const { return isIdle; } }; -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; diseqcCommands = NULL; tunerStatus = tsIdle; + isIdle = false; if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power SetDescription("tuner on frontend %d/%d", adapter, frontend); @@ -305,6 +313,8 @@ cDvbTuner::~cDvbTuner() newSet.Broadcast(); locked.Broadcast(); Cancel(3); + if (dvbdevice && dvbdevice->IsSubDevice()) + CloseFrontend(); } bool cDvbTuner::IsTunedTo(const cChannel *Channel) const @@ -339,8 +349,49 @@ bool cDvbTuner::Locked(int TimeoutMs) return tunerStatus >= tsLocked; } +bool cDvbTuner::SetIdle(bool Idle) +{ + if (isIdle == Idle) + return true; + isIdle = Idle; + if (Idle) + return CloseFrontend(); + return OpenFrontend(); +} + +bool cDvbTuner::OpenFrontend(void) +{ + 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; + if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2) +#ifdef LNB_SHARING_VERSION + if (lnbSendSignals) +#endif + CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must explicitly turn on LNB power + 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; +} + bool cDvbTuner::GetFrontendStatus(fe_status_t &Status, int TimeoutMs) { + if (!OpenFrontend()) + return false; if (TimeoutMs) { cPoller Poller(fd_frontend); if (Poller.Poll(TimeoutMs)) { @@ -367,6 +418,8 @@ static unsigned int FrequencyToHz(unsigned int f) 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);\ @@ -526,9 +579,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, 10)) - Status = NewStatus; + if (!isIdle) { + fe_status_t NewStatus; + if (GetFrontendStatus(NewStatus, 10)) + Status = NewStatus; + } cMutexLock MutexLock(&mutex); switch (tunerStatus) { case tsIdle: @@ -661,7 +716,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 +734,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): @@ -718,7 +774,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 @@ -823,6 +879,31 @@ bool cDvbDevice::Ready(void) 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::CanScanForEPG(void) const +{ + return !IsIdle() && !dvbTuner->IsIdle() && ((ciAdapter == NULL) || !ciAdapter->IsIdle()); +} + bool cDvbDevice::HasCi(void) { return ciAdapter; diff --git a/dvbdevice.h b/dvbdevice.h index ff606fd..7ca1a87 100644 --- a/dvbdevice.h +++ b/dvbdevice.h @@ -102,7 +102,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: @@ -123,10 +123,13 @@ 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); + virtual bool SetIdleDevice(bool Idle, bool TestOnly); + virtual bool CanScanForEPG(void) const; + // Common Interface facilities: private: diff --git a/eitscan.c b/eitscan.c index 2b43e71..ff5e3e4 100644 --- a/eitscan.c +++ b/eitscan.c @@ -143,7 +143,7 @@ void cEITScanner::Process(void) bool AnyDeviceSwitched = false; for (int i = 0; i < cDevice::NumDevices(); i++) { cDevice *Device = cDevice::GetDevice(i); - if (Device) { + if (Device && Device->CanScanForEPG()) { for (cScanData *ScanData = scanList->First(); ScanData; ScanData = scanList->Next(ScanData)) { const cChannel *Channel = ScanData->GetChannel(); if (Channel) {