@@ -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;
@@ -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;
@@ -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;
@@ -16,6 +16,7 @@
class cDvbSdFfDevice : public cDvbDevice {
private:
+ int frontend;
int fd_osd, fd_audio, fd_video, fd_stc;
bool outputOnly;
protected:
@@ -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;
}
@@ -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
@@ -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;
@@ -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);