Am 16.11.2011 23:26, schrieb Klaus Schmidinger:
On 16.11.2011 19:16, L. Hanisch wrote:
Am 16.11.2011 00:08, schrieb Klaus Schmidinger:
That is also my understanding of multi frontend devices.
If an "adapter" has several "frontends" only one of them can
be active at any given time. This has nothing to do with
any "explosives" (excuse the pun ;-) and will be implemented
in the core VDR code as time permits. Right now I'm cleaning up
the "lnb sharing" (aka "device bonding") stuff and will hopefully
find more time for VDR development by the end of the year (and
thereafter).

If you don't mind I would try to prefabricate something.
On a first guess: would you combine the multiple frontends of an adapter in one 
cDvbDevice? I think this would be
better than having multiple cDvbDevices which must interact somehow with each 
other.

Sure there will be one cDvbDevice per adapter for a multi-frontend device
where only one frontend can be active at any time.
If (like on the TT-S2 6400) there are several frontends that can be
active simultaneously, then there shall be separate adapters for each
frontend, and thus a separate cDvbDevice for each adapter.

Here's a first "quick'n'dirty" patch. Since my hardware hasn't arrived yet I tested with a DVB-T and DVB-C stick and sym-linked the devices within one adapter. I have no ca-devices in this setup.
 Switching between C and T channels works here, but it's not really tested with 
timers/recordings etc.

I don't have a FF card, so the patches for the plugins are more of "remove compiler warnings" only. One have to think about cDvbDeviceProbe and the parameters. A frontend argument doesn't make much sense now.

Note, though, that support for such devices will most likely not
go into VDR for version 2. I'm trying to wrap things up in order
to make a stable version 2, and after that will address new things
like this.

 I'm fine with this and looking forward to it. A new stable release would be 
fine! Xmas is next door... :)

Lars.
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c 
b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
index ff3f953..e7fb935 100644
--- a/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
+++ b/PLUGINS/src/dvbhddevice/dvbhdffdevice.c
@@ -26,7 +26,8 @@
 int cDvbHdFfDevice::devHdffOffset = -1;
 
 cDvbHdFfDevice::cDvbHdFfDevice(int Adapter, int Frontend)
-:cDvbDevice(Adapter, Frontend)
+:cDvbDevice(Adapter)
+,frontend(Frontend)
 {
   spuDecoder = NULL;
   audioChannel = 0;
diff --git a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h 
b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
index 4dcfb6a..62540da 100644
--- a/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
+++ b/PLUGINS/src/dvbhddevice/dvbhdffdevice.h
@@ -17,12 +17,13 @@
 
 class cDvbHdFfDevice : public cDvbDevice {
 private:
+  int frontend;
   int fd_osd, fd_audio, fd_video;
 protected:
   virtual void MakePrimaryDevice(bool On);
 public:
   static bool Probe(int Adapter, int Frontend);
-  cDvbHdFfDevice(int Adapter, int Frontend);
+  cDvbHdFfDevice(int Adapter, int Frontend = 0);
   virtual ~cDvbHdFfDevice();
   virtual bool HasDecoder(void) const;
 
diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c 
b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
index 17f842b..68031b5 100644
--- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
+++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c
@@ -24,7 +24,8 @@
 int cDvbSdFfDevice::devVideoOffset = -1;
 
 cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend, bool OutputOnly)
-:cDvbDevice(Adapter, Frontend)
+:cDvbDevice(Adapter)
+,frontend(Frontend)
 {
   spuDecoder = NULL;
   digitalAudio = false;
diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h 
b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h
index bd74cde..c060859 100644
--- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h
+++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h
@@ -16,6 +16,7 @@
 
 class cDvbSdFfDevice : public cDvbDevice {
 private:
+  int frontend;
   int fd_osd, fd_audio, fd_video, fd_stc;
   bool outputOnly;
 protected:
diff --git a/dvbci.c b/dvbci.c
index 5289bbd..66dddc8 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 Ca)
 {
   device = Device;
   SetDescription("CI adapter on device %d", device->DeviceNumber());
   fd = Fd;
+  adapter = Adapter;
+  ca = Ca;
+  OpenCa();
   ca_caps_t Caps;
   if (ioctl(fd, CA_GET_CAP, &Caps) == 0) {
      if ((Caps.slot_type & CA_CI_LINK) != 0) {
@@ -41,10 +44,29 @@ cDvbCiAdapter::cDvbCiAdapter(cDevice *Device, int Fd)
 cDvbCiAdapter::~cDvbCiAdapter()
 {
   Cancel(3);
+  CloseCa();
+}
+
+bool cDvbCiAdapter::OpenCa(void)
+{
+  if (fd >= 0)
+     return true;
+  fd = cDvbDevice::DvbOpen(DEV_DVB_CA, adapter, ca, O_RDWR);
+  return (fd >= 0);
+}
+
+void cDvbCiAdapter::CloseCa(void)
+{
+  if (fd < 0)
+     return;
+  close(fd);
+  fd = -1;
 }
 
 int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength)
 {
+  if (fd < 0)
+     return 0;
   if (Buffer && MaxLength > 0) {
      struct pollfd pfd[1];
      pfd[0].fd = fd;
@@ -61,6 +83,8 @@ int cDvbCiAdapter::Read(uint8_t *Buffer, int MaxLength)
 
 void cDvbCiAdapter::Write(const uint8_t *Buffer, int Length)
 {
+  if (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 +93,8 @@ void cDvbCiAdapter::Write(const uint8_t *Buffer, int Length)
 
 bool cDvbCiAdapter::Reset(int Slot)
 {
+  if (fd < 0)
+     return false;
   if (ioctl(fd, CA_RESET, 1 << Slot) != -1)
      return true;
   else
@@ -78,6 +104,8 @@ bool cDvbCiAdapter::Reset(int Slot)
 
 eModuleStatus cDvbCiAdapter::ModuleStatus(int Slot)
 {
+  if (fd < 0)
+     return msNone;
   ca_slot_info_t sinfo;
   sinfo.num = Slot;
   if (ioctl(fd, CA_GET_SLOT_INFO, &sinfo) != -1) {
@@ -99,10 +127,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 Ca)
 {
   // TODO check whether a CI is actually present?
   if (Device)
-     return new cDvbCiAdapter(Device, Fd);
+     return new cDvbCiAdapter(Device, Fd, Adapter, Ca);
   return NULL;
 }
diff --git a/dvbci.h b/dvbci.h
index adbe40d..988ecca 100644
--- a/dvbci.h
+++ b/dvbci.h
@@ -16,16 +16,22 @@ class cDvbCiAdapter : public cCiAdapter {
 private:
   cDevice *device;
   int fd;
+  int adapter;
+  int ca;
+  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 Ca = -1);
 public:
   virtual ~cDvbCiAdapter();
-  static cDvbCiAdapter *CreateCiAdapter(cDevice *Device, int Fd);
+  static cDvbCiAdapter *CreateCiAdapter(cDevice *Device, int Fd, int Adapter = 
-1, int Ca = -1);
   };
 
 #endif //__DVBCI_H
diff --git a/dvbdevice.c b/dvbdevice.c
index a97f274..24cefc9 100644
--- a/dvbdevice.c
+++ b/dvbdevice.c
@@ -276,8 +276,10 @@ private:
   bool GetFrontendStatus(fe_status_t &Status) const;
   bool SetFrontend(void);
   virtual void Action(void);
+  bool OpenFrontend(void);
+  bool CloseFrontend(void);
 public:
-  cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, 
fe_delivery_system FrontendType);
+  cDvbTuner(int Device, int Adapter, int Frontend, fe_delivery_system 
FrontendType);
   virtual ~cDvbTuner();
   const cChannel *GetTransponder(void) const { return &channel; }
   uint32_t SubsystemId(void) const { return subsystemId; }
@@ -288,10 +290,10 @@ public:
   int GetSignalQuality(void) const;
   };
 
-cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int Adapter, int Frontend, 
fe_delivery_system FrontendType)
+cDvbTuner::cDvbTuner(int Device, int Adapter, int Frontend, fe_delivery_system 
FrontendType)
 {
   device = Device;
-  fd_frontend = Fd_Frontend;
+  fd_frontend = -1;
   adapter = Adapter;
   frontend = Frontend;
   frontendType = FrontendType;
@@ -301,8 +303,7 @@ cDvbTuner::cDvbTuner(int Device, int Fd_Frontend, int 
Adapter, int Frontend, fe_
   lastTimeoutReport = 0;
   diseqcCommands = NULL;
   tunerStatus = tsIdle;
-  if (frontendType == SYS_DVBS || frontendType == SYS_DVBS2)
-     CHECK(ioctl(fd_frontend, FE_SET_VOLTAGE, SEC_VOLTAGE_13)); // must 
explicitly turn on LNB power
+  OpenFrontend();
   SetDescription("tuner on frontend %d/%d", adapter, frontend);
   Start();
 }
@@ -313,6 +314,7 @@ cDvbTuner::~cDvbTuner()
   newSet.Broadcast();
   locked.Broadcast();
   Cancel(3);
+  CloseFrontend();
 }
 
 bool cDvbTuner::IsTunedTo(const cChannel *Channel) const
@@ -698,6 +700,34 @@ void cDvbTuner::Action(void)
         }
 }
 
+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
+  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 {
@@ -778,69 +808,98 @@ const char *DeliverySystems[] = {
   NULL
   };
 
-cDvbDevice::cDvbDevice(int Adapter, int Frontend)
+cDvbDevice::cDvbDevice(int Adapter)
 {
+  numFrontends = 0;
+  currentFrontend = 0;
   adapter = Adapter;
-  frontend = Frontend;
   ciAdapter = NULL;
   dvbTuner = NULL;
-  frontendType = SYS_UNDEFINED;
   numProvidedSystems = 0;
-
-  // Devices that are present on all card types:
-
-  int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | 
O_NONBLOCK);
-
-  // Common Interface:
-
-  fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR);
-  if (fd_ca >= 0)
-     ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca);
-
+  int fd_frontend = -1;
   // The DVR device (will be opened and closed as needed):
-
   fd_dvr = -1;
 
-  // We only check the devices that must be present - the others will be 
checked before accessing them://XXX
-
-  if (fd_frontend >= 0) {
-     if (ioctl(fd_frontend, FE_GET_INFO, &frontendInfo) >= 0) {
-        switch (frontendInfo.type) {
-          case FE_QPSK: frontendType = (frontendInfo.caps & 
FE_CAN_2G_MODULATION) ? SYS_DVBS2 : SYS_DVBS; break;
-          case FE_OFDM: frontendType = SYS_DVBT; break;
-          case FE_QAM:  frontendType = SYS_DVBC_ANNEX_AC; break;
-          case FE_ATSC: frontendType = SYS_ATSC; break;
-          default: esyslog("ERROR: unknown frontend type %d on frontend 
%d/%d", frontendInfo.type, adapter, frontend);
-          }
-        }
-     else
-        LOG_ERROR;
-     if (frontendType != SYS_UNDEFINED) {
-        numProvidedSystems++;
-        if (frontendType == SYS_DVBS2)
-           numProvidedSystems++;
-        char Modulations[64];
-        char *p = Modulations;
-        if (frontendInfo.caps & FE_CAN_QPSK)    { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(QPSK, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_16)  { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(QAM_16, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_32)  { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(QAM_32, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_64)  { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(QAM_64, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_128) { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(QAM_128, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_QAM_256) { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(QAM_256, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_8VSB)    { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(VSB_8, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_16VSB)   { numProvidedSystems++; p += 
sprintf(p, ",%s", MapToUserString(VSB_16, ModulationValues)); }
-        if (frontendInfo.caps & FE_CAN_TURBO_FEC){numProvidedSystems++; p += 
sprintf(p, ",%s", "TURBO_FEC"); }
-        if (p != Modulations)
-           p = Modulations + 1; // skips first ','
-        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);
-        }
+  for (int f = 0; (numFrontends < MAXDVBFRONTENDS) && Exists(adapter, f); f++) 
{
+      frontends[numFrontends].frontend = f;
+      frontends[numFrontends].demux = frontends[numFrontends].frontend;
+      frontends[numFrontends].dvr = frontends[numFrontends].frontend;
+      frontends[numFrontends].ca = frontends[numFrontends].frontend;
+      frontends[numFrontends].frontendType = SYS_UNDEFINED;
+
+      // Devices that are present on all card types:
+
+      fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, 
frontends[numFrontends].frontend, O_RDWR | O_NONBLOCK);
+
+      if (fd_frontend >= 0) {
+         // Look for the right devices
+         while ((frontends[numFrontends].demux >= 0) && !Exists(DEV_DVB_DEMUX, 
adapter, frontends[numFrontends].demux))
+               frontends[numFrontends].demux--;
+         if (frontends[numFrontends].demux < 0) {
+            frontends[numFrontends].demux = frontends[numFrontends].frontend;
+            esyslog("frontend %d/%d has no demux device", adapter, 
frontends[numFrontends].frontend);
+            }
+         else if (frontends[numFrontends].demux != 
frontends[numFrontends].frontend)
+            isyslog("frontend %d/%d will use demux%d", adapter, 
frontends[numFrontends].frontend, frontends[numFrontends].demux);
+
+         while ((frontends[numFrontends].dvr >= 0) && !Exists(DEV_DVB_DVR, 
adapter, frontends[numFrontends].dvr))
+               frontends[numFrontends].dvr--;
+         if (frontends[numFrontends].dvr < 0) {
+            frontends[numFrontends].dvr = frontends[numFrontends].frontend;
+            esyslog("frontend %d/%d has no dvr device", adapter, 
frontends[numFrontends].frontend);
+            }
+         else if (frontends[numFrontends].dvr != 
frontends[numFrontends].frontend)
+            isyslog("frontend %d/%d will use dvr%d", adapter, 
frontends[numFrontends].frontend, frontends[numFrontends].dvr);
+
+         while ((frontends[numFrontends].ca >= 0) && !Exists(DEV_DVB_CA, 
adapter, frontends[numFrontends].ca))
+               frontends[numFrontends].ca--;
+         if ((frontends[numFrontends].ca >= 0) && (frontends[numFrontends].ca 
!= frontends[numFrontends].frontend))
+            isyslog("frontend %d/%d will use ca%d", adapter, 
frontends[numFrontends].frontend, frontends[numFrontends].ca);
+
+         if (ioctl(fd_frontend, FE_GET_INFO, 
&frontends[numFrontends].frontendInfo) >= 0) {
+            switch (frontends[numFrontends].frontendInfo.type) {
+              case FE_QPSK: frontends[numFrontends].frontendType = 
(frontends[numFrontends].frontendInfo.caps & FE_CAN_2G_MODULATION) ? SYS_DVBS2 
: SYS_DVBS; break;
+              case FE_OFDM: frontends[numFrontends].frontendType = SYS_DVBT; 
break;
+              case FE_QAM:  frontends[numFrontends].frontendType = 
SYS_DVBC_ANNEX_AC; break;
+              case FE_ATSC: frontends[numFrontends].frontendType = SYS_ATSC; 
break;
+              default: esyslog("ERROR: unknown frontend type %d on frontend 
%d/%d", frontends[numFrontends].frontendInfo.type, adapter, 
frontends[numFrontends].frontend);
+              }
+            }
+         else
+            LOG_ERROR;
+         if (frontends[numFrontends].frontendType != SYS_UNDEFINED) {
+            numProvidedSystems++;
+            if (frontends[numFrontends].frontendType == SYS_DVBS2)
+               numProvidedSystems++;
+            char Modulations[64];
+            char *p = Modulations;
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QPSK)    { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QPSK, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_16)  { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_16, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_32)  { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_32, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_64)  { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_64, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_128) { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_128, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_QAM_256) { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(QAM_256, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_8VSB)    { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_8, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & FE_CAN_16VSB)   { 
numProvidedSystems++; p += sprintf(p, ",%s", MapToUserString(VSB_16, 
ModulationValues)); }
+            if (frontends[numFrontends].frontendInfo.caps & 
FE_CAN_TURBO_FEC){numProvidedSystems++; p += sprintf(p, ",%s", "TURBO_FEC"); }
+            if (p != Modulations)
+               p = Modulations + 1; // skips first ','
+            else
+               p = (char *)"unknown modulations";
+            isyslog("frontend %d/%d provides %s with %s (\"%s\")", adapter, 
frontends[numFrontends].frontend, 
DeliverySystems[frontends[numFrontends].frontendType], p, 
frontends[numFrontends].frontendInfo.name);
+            numFrontends++;
+            }
+         close (fd_frontend);
+         }
+      else
+         esyslog("ERROR: can't open DVB device %d/%d", adapter, 
frontends[numFrontends].frontend);
+      }
+  if (numFrontends > 0) {
+     dvbTuner = new cDvbTuner(CardIndex() + 1, adapter, 
frontends[currentFrontend].frontend, frontends[currentFrontend].frontendType);
+     // Common Interface:
+     if (frontends[currentFrontend].ca >= 0)
+        ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, -1, adapter, 
frontends[currentFrontend].ca);
      }
-  else
-     esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend);
-
   StartSectionHandler();
 }
 
@@ -869,7 +928,12 @@ int cDvbDevice::DvbOpen(const char *Name, int Adapter, int 
Frontend, int Mode, b
 
 bool cDvbDevice::Exists(int Adapter, int Frontend)
 {
-  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
+  return Exists(DEV_DVB_FRONTEND, Adapter, Frontend);
+}
+
+bool cDvbDevice::Exists(const char *Name, int Adapter, int Frontend)
+{
+  cString FileName = DvbName(Name, Adapter, Frontend);
   if (access(FileName, F_OK) == 0) {
      int f = open(FileName, O_RDONLY);
      if (f >= 0) {
@@ -884,16 +948,16 @@ bool cDvbDevice::Exists(int Adapter, int Frontend)
   return false;
 }
 
-bool cDvbDevice::Probe(int Adapter, int Frontend)
+bool cDvbDevice::Probe(int Adapter)
 {
-  cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend);
-  dsyslog("probing %s", *FileName);
+  cString adapterName = cString::sprintf("%s%d", DEV_DVB_ADAPTER, Adapter);
+  dsyslog("probing %s", *adapterName);
   for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = 
DvbDeviceProbes.Next(dp)) {
-      if (dp->Probe(Adapter, Frontend))
+      if (dp->Probe(Adapter, 0))
          return true; // a plugin has created the actual device
       }
   dsyslog("creating cDvbDevice");
-  new cDvbDevice(Adapter, Frontend); // it's a "budget" device
+  new cDvbDevice(Adapter); // it's a "budget" device
   return true;
 }
 
@@ -906,23 +970,18 @@ bool cDvbDevice::Initialize(void)
   int Checked = 0;
   int Found = 0;
   for (int Adapter = 0; ; Adapter++) {
-      for (int Frontend = 0; ; Frontend++) {
-          if (Exists(Adapter, Frontend)) {
-             if (Checked++ < MAXDVBDEVICES) {
-                if (UseDevice(NextCardIndex())) {
-                   if (Probe(Adapter, Frontend))
-                      Found++;
-                   }
-                else
-                   NextCardIndex(1); // skips this one
-                }
-             }
-          else if (Frontend == 0)
-             goto LastAdapter;
-          else
-             goto NextAdapter;
-          }
-      NextAdapter: ;
+      if (Exists(DEV_DVB_FRONTEND, Adapter, 0)) {
+         if (Checked++ < MAXDVBDEVICES) {
+            if (UseDevice(NextCardIndex())) {
+               if (Probe(Adapter))
+                  Found++;
+               }
+            else
+               NextCardIndex(1); // skips this one
+            }
+         }
+         else
+            goto LastAdapter;
       }
 LastAdapter:
   NextCardIndex(MAXDVBDEVICES - Checked); // skips the rest
@@ -952,7 +1011,7 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool 
On)
      memset(&pesFilterParams, 0, sizeof(pesFilterParams));
      if (On) {
         if (Handle->handle < 0) {
-           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | 
O_NONBLOCK, true);
+           Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, 
frontends[currentFrontend].demux, O_RDWR | O_NONBLOCK, true);
            if (Handle->handle < 0) {
               LOG_ERROR;
               return false;
@@ -987,7 +1046,7 @@ bool cDvbDevice::SetPid(cPidHandle *Handle, int Type, bool 
On)
 
 int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask)
 {
-  cString FileName = DvbName(DEV_DVB_DEMUX, adapter, frontend);
+  cString FileName = DvbName(DEV_DVB_DEMUX, adapter, 
frontends[currentFrontend].demux);
   int f = open(FileName, O_RDWR | O_NONBLOCK);
   if (f >= 0) {
      dmx_sct_filter_params sctFilterParams;
@@ -1014,32 +1073,43 @@ void cDvbDevice::CloseFilter(int Handle)
   close(Handle);
 }
 
-bool cDvbDevice::ProvidesSource(int Source) const
+int cDvbDevice::GetFrontend(int Source) const
 {
   int type = Source & cSource::st_Mask;
-  return type == cSource::stNone
-      || type == cSource::stAtsc  && (frontendType == SYS_ATSC)
-      || type == cSource::stCable && (frontendType == SYS_DVBC_ANNEX_AC || 
frontendType == SYS_DVBC_ANNEX_B)
-      || type == cSource::stSat   && (frontendType == SYS_DVBS || frontendType 
== SYS_DVBS2)
-      || type == cSource::stTerr  && (frontendType == SYS_DVBT);
+  if (type == cSource::stNone)
+     return 0; // can this happen?
+  for (int f = 0; f < numFrontends; f++) {
+      if (type == cSource::stAtsc  && (frontends[f].frontendType == SYS_ATSC)
+          || type == cSource::stCable && (frontends[f].frontendType == 
SYS_DVBC_ANNEX_AC || frontends[f].frontendType == SYS_DVBC_ANNEX_B)
+          || type == cSource::stSat   && (frontends[f].frontendType == 
SYS_DVBS || frontends[f].frontendType == SYS_DVBS2)
+          || type == cSource::stTerr  && (frontends[f].frontendType == 
SYS_DVBT))
+         return f;
+      }
+  return -1;
+}
+
+bool cDvbDevice::ProvidesSource(int Source) const
+{
+  return (GetFrontend(Source) >= 0);
 }
 
 bool cDvbDevice::ProvidesTransponder(const cChannel *Channel) const
 {
-  if (!ProvidesSource(Channel->Source()))
+  int f = GetFrontend(Channel->Source());
+  if (f < 0)
      return false; // doesn't provide source
   cDvbTransponderParameters dtp(Channel->Parameters());
-  if (dtp.System() == SYS_DVBS2 && frontendType == SYS_DVBS ||
-     dtp.Modulation() == QPSK     && !(frontendInfo.caps & FE_CAN_QPSK) ||
-     dtp.Modulation() == QAM_16   && !(frontendInfo.caps & FE_CAN_QAM_16) ||
-     dtp.Modulation() == QAM_32   && !(frontendInfo.caps & FE_CAN_QAM_32) ||
-     dtp.Modulation() == QAM_64   && !(frontendInfo.caps & FE_CAN_QAM_64) ||
-     dtp.Modulation() == QAM_128  && !(frontendInfo.caps & FE_CAN_QAM_128) ||
-     dtp.Modulation() == QAM_256  && !(frontendInfo.caps & FE_CAN_QAM_256) ||
-     dtp.Modulation() == QAM_AUTO && !(frontendInfo.caps & FE_CAN_QAM_AUTO) ||
-     dtp.Modulation() == VSB_8    && !(frontendInfo.caps & FE_CAN_8VSB) ||
-     dtp.Modulation() == VSB_16   && !(frontendInfo.caps & FE_CAN_16VSB) ||
-     dtp.Modulation() == PSK_8    && !(frontendInfo.caps & FE_CAN_TURBO_FEC) 
&& dtp.System() == SYS_DVBS) // "turbo fec" is a non standard FEC used by North 
American broadcasters - this is a best guess to determine this condition
+  if (dtp.System() == SYS_DVBS2 && frontends[f].frontendType == SYS_DVBS ||
+     dtp.Modulation() == QPSK     && !(frontends[f].frontendInfo.caps & 
FE_CAN_QPSK) ||
+     dtp.Modulation() == QAM_16   && !(frontends[f].frontendInfo.caps & 
FE_CAN_QAM_16) ||
+     dtp.Modulation() == QAM_32   && !(frontends[f].frontendInfo.caps & 
FE_CAN_QAM_32) ||
+     dtp.Modulation() == QAM_64   && !(frontends[f].frontendInfo.caps & 
FE_CAN_QAM_64) ||
+     dtp.Modulation() == QAM_128  && !(frontends[f].frontendInfo.caps & 
FE_CAN_QAM_128) ||
+     dtp.Modulation() == QAM_256  && !(frontends[f].frontendInfo.caps & 
FE_CAN_QAM_256) ||
+     dtp.Modulation() == QAM_AUTO && !(frontends[f].frontendInfo.caps & 
FE_CAN_QAM_AUTO) ||
+     dtp.Modulation() == VSB_8    && !(frontends[f].frontendInfo.caps & 
FE_CAN_8VSB) ||
+     dtp.Modulation() == VSB_16   && !(frontends[f].frontendInfo.caps & 
FE_CAN_16VSB) ||
+     dtp.Modulation() == PSK_8    && !(frontends[f].frontendInfo.caps & 
FE_CAN_TURBO_FEC) && dtp.System() == SYS_DVBS) // "turbo fec" is a non standard 
FEC used by North American broadcasters - this is a best guess to determine 
this condition
      return false; // requires modulation system which frontend doesn't provide
   if (!cSource::IsSat(Channel->Source()) ||
      !Setup.DiSEqC || Diseqcs.Get(CardIndex() + 1, Channel->Source(), 
Channel->Frequency(), dtp.Polarization()))
@@ -1113,6 +1183,28 @@ bool cDvbDevice::IsTunedToTransponder(const cChannel 
*Channel)
 
 bool cDvbDevice::SetChannelDevice(const cChannel *Channel, bool LiveView)
 {
+  if (numFrontends > 1) {
+     int f = GetFrontend(Channel->Source());
+     if (f < 0)
+        return false;
+     if (currentFrontend != f) {
+        isyslog("switching frontend on adapter %d from %d to %d", adapter, 
frontends[currentFrontend].frontend, frontends[f].frontend);
+        StopSectionHandler();
+        if (dvbTuner) {
+           delete dvbTuner;
+           dvbTuner = NULL;
+           }
+        if (ciAdapter) {
+           delete ciAdapter;
+           ciAdapter = NULL;
+           }
+        currentFrontend = f;
+        dvbTuner = new cDvbTuner(CardIndex() + 1, adapter, 
frontends[currentFrontend].frontend, frontends[currentFrontend].frontendType);
+        if (frontends[currentFrontend].ca >= 0)
+           ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, -1, adapter, 
frontends[currentFrontend].ca);
+        StartSectionHandler();
+        }
+     }
   if (dvbTuner)
      dvbTuner->Set(Channel);
   return true;
@@ -1131,7 +1223,7 @@ void cDvbDevice::SetTransferModeForDolbyDigital(int Mode)
 bool cDvbDevice::OpenDvr(void)
 {
   CloseDvr();
-  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, O_RDONLY | O_NONBLOCK, 
true);
+  fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontends[currentFrontend].dvr, 
O_RDONLY | O_NONBLOCK, true);
   if (fd_dvr >= 0)
      tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1);
   return fd_dvr >= 0;
diff --git a/dvbdevice.h b/dvbdevice.h
index e1842b7..a127da7 100644
--- a/dvbdevice.h
+++ b/dvbdevice.h
@@ -20,6 +20,7 @@
 #endif
 
 #define MAXDVBDEVICES  8
+#define MAXDVBFRONTENDS 8
 
 #define DEV_VIDEO         "/dev/video"
 #define DEV_DVB_ADAPTER   "/dev/dvb/adapter"
@@ -101,14 +102,25 @@ class cDvbTuner;
 
 /// The cDvbDevice implements a DVB device which can be accessed through the 
Linux DVB driver API.
 
+struct tDvbFrontend {
+  int frontend;
+  int demux;
+  int dvr;
+  int ca;
+
+  dvb_frontend_info frontendInfo;
+  fe_delivery_system frontendType;
+  };
+
 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:
   static bool Exists(int Adapter, int Frontend);
+  static bool Exists(const char *Name, int Adapter, int Frontend);
          ///< Checks whether the given adapter/frontend exists.
-  static bool Probe(int Adapter, int Frontend);
+  static bool Probe(int Adapter);
          ///< Probes for existing DVB devices.
 public:
   static bool Initialize(void);
@@ -116,14 +128,17 @@ public:
          ///< Must be called before accessing any DVB functions.
          ///< \return True if any devices are available.
 protected:
-  int adapter, frontend;
+  int adapter;
 private:
-  dvb_frontend_info frontendInfo;
+  tDvbFrontend frontends[MAXDVBFRONTENDS];
+  int numFrontends;
+  int currentFrontend;
+  int GetFrontend(int Source) const;
+
   int numProvidedSystems;
-  fe_delivery_system frontendType;
-  int fd_dvr, fd_ca;
+  int fd_dvr;
 public:
-  cDvbDevice(int Adapter, int Frontend);
+  cDvbDevice(int Adapter);
   virtual ~cDvbDevice();
   virtual bool Ready(void);
 
_______________________________________________
vdr mailing list
vdr@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr

Reply via email to