From af494287cf131d152f1a925614ded6def491b3e0 Mon Sep 17 00:00:00 2001 From: Klaus Schmidinger Date: Mon, 4 Jan 2010 14:16:11 +0100 Subject: Added support for DVB cards with multiple fontends --- HISTORY | 5 +- PLUGINS/src/dvbsddevice/HISTORY | 3 +- PLUGINS/src/dvbsddevice/dvbsdffdevice.c | 28 ++++---- PLUGINS/src/dvbsddevice/dvbsdffdevice.h | 6 +- dvbdevice.c | 123 ++++++++++++++++++-------------- dvbdevice.h | 16 +++-- 6 files changed, 104 insertions(+), 77 deletions(-) diff --git a/HISTORY b/HISTORY index 8353b9ab..7776a803 100644 --- a/HISTORY +++ b/HISTORY @@ -6197,7 +6197,7 @@ Video Disk Recorder Revision History - Fixed the default value for "Pause key handling" in the MANUAL (reported by Diego Pierotto). -2010-01-03: Version 1.7.11 +2010-01-04: Version 1.7.11 - Fixed resetting the file size when regenerating the index file. - The new function cDevice::PatPmtParser() can be used in derived devices to access @@ -6270,3 +6270,6 @@ Video Disk Recorder Revision History - After a CLRE command, no further EPG processing is now done for 10 seconds, so that data sent with subsequent PUTE commands doesn't interfere with data from the broadcasters (suggested by Helmut Auer). +- Added support for DVB cards with multiple fontends. Note that this only + works for DVB cards where each frontend can be used independently of all + the others on the same adapter. diff --git a/PLUGINS/src/dvbsddevice/HISTORY b/PLUGINS/src/dvbsddevice/HISTORY index d2b0f1f6..18cd6250 100644 --- a/PLUGINS/src/dvbsddevice/HISTORY +++ b/PLUGINS/src/dvbsddevice/HISTORY @@ -5,7 +5,8 @@ VDR Plugin 'dvbsddevice' Revision History - Initial revision. -2010-01-01: Version 0.0.2 +2010-01-04: Version 0.0.2 - Calling the MakePrimaryDevice() function of the base class to allow the cDevice to stop displaying subtitles. +- Added support for DVB cards with multiple fontends. diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c index 61913776..21a60a52 100644 --- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.c +++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.c @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: dvbsdffdevice.c 2.24 2010/01/01 15:03:02 kls Exp $ + * $Id: dvbsdffdevice.c 2.25 2010/01/04 12:56:56 kls Exp $ */ #include "dvbsdffdevice.h" @@ -23,8 +23,8 @@ int cDvbSdFfDevice::devVideoOffset = -1; -cDvbSdFfDevice::cDvbSdFfDevice(int n) -:cDvbDevice(n) +cDvbSdFfDevice::cDvbSdFfDevice(int Adapter, int Frontend) +:cDvbDevice(Adapter, Frontend) { spuDecoder = NULL; digitalAudio = false; @@ -32,10 +32,10 @@ cDvbSdFfDevice::cDvbSdFfDevice(int n) // Devices that are only present on cards with decoders: - fd_osd = DvbOpen(DEV_DVB_OSD, n, O_RDWR); - fd_video = DvbOpen(DEV_DVB_VIDEO, n, O_RDWR | O_NONBLOCK); - fd_audio = DvbOpen(DEV_DVB_AUDIO, n, O_RDWR | O_NONBLOCK); - fd_stc = DvbOpen(DEV_DVB_DEMUX, n, O_RDWR); + fd_osd = DvbOpen(DEV_DVB_OSD, adapter, frontend, O_RDWR); + fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); + fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); + fd_stc = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR); // The offset of the /dev/video devices: @@ -317,7 +317,7 @@ bool cDvbSdFfDevice::SetPid(cPidHandle *Handle, int Type, bool On) memset(&pesFilterParams, 0, sizeof(pesFilterParams)); if (On) { if (Handle->handle < 0) { - Handle->handle = DvbOpen(DEV_DVB_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true); + Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true); if (Handle->handle < 0) { LOG_ERROR; return false; @@ -507,8 +507,8 @@ bool cDvbSdFfDevice::SetPlayMode(ePlayMode PlayMode) { if (PlayMode != pmExtern_THIS_SHOULD_BE_AVOIDED && fd_video < 0 && fd_audio < 0) { // reopen the devices - fd_video = DvbOpen(DEV_DVB_VIDEO, CardIndex(), O_RDWR | O_NONBLOCK); - fd_audio = DvbOpen(DEV_DVB_AUDIO, CardIndex(), O_RDWR | O_NONBLOCK); + fd_video = DvbOpen(DEV_DVB_VIDEO, adapter, frontend, O_RDWR | O_NONBLOCK); + fd_audio = DvbOpen(DEV_DVB_AUDIO, adapter, frontend, O_RDWR | O_NONBLOCK); SetVideoFormat(Setup.VideoFormat); } @@ -756,7 +756,7 @@ int cDvbSdFfDevice::PlayTsAudio(const uchar *Data, int Length) // --- cDvbSdFfDeviceProbe --------------------------------------------------- -bool cDvbSdFfDeviceProbe::Probe(int Adapter) +bool cDvbSdFfDeviceProbe::Probe(int Adapter, int Frontend) { static uint32_t SubsystemIds[] = { 0x110A0000, // Fujitsu Siemens DVB-C @@ -776,13 +776,13 @@ bool cDvbSdFfDeviceProbe::Probe(int Adapter) cReadLine ReadLine; FILE *f = NULL; uint32_t SubsystemId = 0; - FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend0/device/subsystem_vendor", Adapter); + FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_vendor", Adapter, Frontend); if ((f = fopen(FileName, "r")) != NULL) { if (char *s = ReadLine.Read(f)) SubsystemId = strtoul(s, NULL, 0) << 16; fclose(f); } - FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend0/device/subsystem_device", Adapter); + FileName = cString::sprintf("/sys/class/dvb/dvb%d.frontend%d/device/subsystem_device", Adapter, Frontend); if ((f = fopen(FileName, "r")) != NULL) { if (char *s = ReadLine.Read(f)) SubsystemId |= strtoul(s, NULL, 0); @@ -791,7 +791,7 @@ bool cDvbSdFfDeviceProbe::Probe(int Adapter) for (uint32_t *sid = SubsystemIds; *sid; sid++) { if (*sid == SubsystemId) { dsyslog("creating cDvbSdFfDevice"); - new cDvbSdFfDevice(Adapter); + new cDvbSdFfDevice(Adapter, Frontend); return true; } } diff --git a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h index ea5f9ffa..b382bf62 100644 --- a/PLUGINS/src/dvbsddevice/dvbsdffdevice.h +++ b/PLUGINS/src/dvbsddevice/dvbsdffdevice.h @@ -3,7 +3,7 @@ * * See the README file for copyright information and how to reach the author. * - * $Id: dvbsdffdevice.h 2.10 2009/12/31 15:36:56 kls Exp $ + * $Id: dvbsdffdevice.h 2.11 2010/01/04 11:01:14 kls Exp $ */ #ifndef __DVBSDFFDEVICE_H @@ -20,7 +20,7 @@ private: protected: virtual void MakePrimaryDevice(bool On); public: - cDvbSdFfDevice(int n); + cDvbSdFfDevice(int Adapter, int Frontend); virtual ~cDvbSdFfDevice(); virtual bool HasDecoder(void) const; @@ -101,7 +101,7 @@ public: class cDvbSdFfDeviceProbe : public cDvbDeviceProbe { public: - virtual bool Probe(int Adapter); + virtual bool Probe(int Adapter, int Frontend); }; #endif //__DVBSDFFDEVICE_H diff --git a/dvbdevice.c b/dvbdevice.c index ee8c9e0b..07e2dbb1 100644 --- a/dvbdevice.c +++ b/dvbdevice.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.c 2.23 2009/12/31 15:38:18 kls Exp $ + * $Id: dvbdevice.c 2.24 2010/01/04 14:06:24 kls Exp $ */ #include "dvbdevice.h" @@ -31,7 +31,7 @@ class cDvbTuner : public cThread { private: enum eTunerStatus { tsIdle, tsSet, tsTuned, tsLocked }; int fd_frontend; - int cardIndex; + int adapter, frontend; int tuneTimeout; int lockTimeout; time_t lastTimeoutReport; @@ -46,17 +46,18 @@ private: bool SetFrontend(void); virtual void Action(void); public: - cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType); + cDvbTuner(int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType); virtual ~cDvbTuner(); bool IsTunedTo(const cChannel *Channel) const; void Set(const cChannel *Channel); bool Locked(int TimeoutMs = 0); }; -cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system FrontendType) +cDvbTuner::cDvbTuner(int Fd_Frontend, int Adapter, int Frontend, fe_delivery_system FrontendType) { fd_frontend = Fd_Frontend; - cardIndex = CardIndex; + adapter = Adapter; + frontend = Frontend; frontendType = FrontendType; tuneTimeout = 0; lockTimeout = 0; @@ -65,7 +66,7 @@ cDvbTuner::cDvbTuner(int Fd_Frontend, int CardIndex, fe_delivery_system Frontend 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 - SetDescription("tuner on device %d", cardIndex + 1); + SetDescription("tuner on frontend %d/%d", adapter, frontend); Start(); } @@ -154,7 +155,7 @@ bool cDvbTuner::SetFrontend(void) #define SETCMD(c, d) { Frontend[CmdSeq.num].cmd = (c);\ Frontend[CmdSeq.num].u.data = (d);\ if (CmdSeq.num++ > MAXFRONTENDCMDS) {\ - esyslog("ERROR: too many tuning commands on frontend %d", cardIndex);\ + esyslog("ERROR: too many tuning commands on frontend %d/%d", adapter, frontend);\ return false;\ }\ } @@ -165,7 +166,7 @@ bool cDvbTuner::SetFrontend(void) CmdSeq.props = Frontend; SETCMD(DTV_CLEAR, 0); if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { - esyslog("ERROR: frontend %d: %m", cardIndex); + esyslog("ERROR: frontend %d/%d: %m", adapter, frontend); return false; } CmdSeq.num = 0; @@ -239,7 +240,7 @@ bool cDvbTuner::SetFrontend(void) SETCMD(DTV_ROLLOFF, channel.RollOff()); } else { - esyslog("ERROR: frontend %d doesn't provide DVB-S2", cardIndex); + esyslog("ERROR: frontend %d/%d doesn't provide DVB-S2", adapter, frontend); return false; } } @@ -285,7 +286,7 @@ bool cDvbTuner::SetFrontend(void) } SETCMD(DTV_TUNE, 0); if (ioctl(fd_frontend, FE_SET_PROPERTY, &CmdSeq) < 0) { - esyslog("ERROR: frontend %d: %m", cardIndex); + esyslog("ERROR: frontend %d/%d: %m", adapter, frontend); return false; } return true; @@ -313,7 +314,7 @@ void cDvbTuner::Action(void) tunerStatus = tsSet; diseqcCommands = NULL; if (time(NULL) - lastTimeoutReport > 60) { // let's not get too many of these - isyslog("frontend %d timed out while tuning to channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder()); + isyslog("frontend %d/%d timed out while tuning to channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder()); lastTimeoutReport = time(NULL); } continue; @@ -322,13 +323,13 @@ void cDvbTuner::Action(void) if (Status & FE_REINIT) { tunerStatus = tsSet; diseqcCommands = NULL; - isyslog("frontend %d was reinitialized", cardIndex); + isyslog("frontend %d/%d was reinitialized", adapter, frontend); lastTimeoutReport = 0; continue; } else if (Status & FE_HAS_LOCK) { if (LostLock) { - isyslog("frontend %d regained lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder()); + isyslog("frontend %d/%d regained lock on channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder()); LostLock = false; } tunerStatus = tsLocked; @@ -337,7 +338,7 @@ void cDvbTuner::Action(void) } else if (tunerStatus == tsLocked) { LostLock = true; - isyslog("frontend %d lost lock on channel %d, tp %d", cardIndex, channel.Number(), channel.Transponder()); + isyslog("frontend %d/%d lost lock on channel %d, tp %d", adapter, frontend, channel.Number(), channel.Transponder()); tunerStatus = tsTuned; Timer.Set(lockTimeout); lastTimeoutReport = 0; @@ -376,8 +377,10 @@ const char *DeliverySystems[] = { NULL }; -cDvbDevice::cDvbDevice(int n) +cDvbDevice::cDvbDevice(int Adapter, int Frontend) { + adapter = Adapter; + frontend = Frontend; ciAdapter = NULL; dvbTuner = NULL; frontendType = SYS_UNDEFINED; @@ -385,11 +388,11 @@ cDvbDevice::cDvbDevice(int n) // Devices that are present on all card types: - int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK); + int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK); // Common Interface: - fd_ca = DvbOpen(DEV_DVB_CA, n, O_RDWR); + fd_ca = DvbOpen(DEV_DVB_CA, adapter, frontend, O_RDWR); if (fd_ca >= 0) ciAdapter = cDvbCiAdapter::CreateCiAdapter(this, fd_ca); @@ -406,7 +409,7 @@ cDvbDevice::cDvbDevice(int n) 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 device %d", frontendInfo.type, CardIndex() + 1); + default: esyslog("ERROR: unknown frontend type %d on frontend %d/%d", frontendInfo.type, adapter, frontend); } } else @@ -415,12 +418,12 @@ cDvbDevice::cDvbDevice(int n) numProvidedSystems++; if (frontendType == SYS_DVBS2) numProvidedSystems++; - isyslog("device %d provides %s (\"%s\")", CardIndex() + 1, DeliverySystems[frontendType], frontendInfo.name); - dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType); + isyslog("frontend %d/%d provides %s (\"%s\")", adapter, frontend, DeliverySystems[frontendType], frontendInfo.name); + dvbTuner = new cDvbTuner(fd_frontend, adapter, frontend, frontendType); } } else - esyslog("ERROR: can't open DVB device %d", n); + esyslog("ERROR: can't open DVB device %d/%d", adapter, frontend); StartSectionHandler(); } @@ -434,34 +437,27 @@ cDvbDevice::~cDvbDevice() // caused segfaults. Besides, the program is about to terminate anyway... } -cString cDvbDevice::DvbName(const char *Name, int n) +cString cDvbDevice::DvbName(const char *Name, int Adapter, int Frontend) { - return cString::sprintf("%s%d/%s%d", DEV_DVB_ADAPTER, n, Name, 0); + return cString::sprintf("%s%d/%s%d", DEV_DVB_ADAPTER, Adapter, Name, Frontend); } -int cDvbDevice::DvbOpen(const char *Name, int n, int Mode, bool ReportError) +int cDvbDevice::DvbOpen(const char *Name, int Adapter, int Frontend, int Mode, bool ReportError) { - cString FileName = DvbName(Name, n); + cString FileName = DvbName(Name, Adapter, Frontend); int fd = open(FileName, Mode); if (fd < 0 && ReportError) LOG_ERROR_STR(*FileName); return fd; } -bool cDvbDevice::Probe(int Adapter) +bool cDvbDevice::Exists(int Adapter, int Frontend) { - cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter); + cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend); if (access(FileName, F_OK) == 0) { - dsyslog("probing %s", *FileName); int f = open(FileName, O_RDONLY); if (f >= 0) { close(f); - for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) { - if (dp->Probe(Adapter)) - return true; // a plugin has created the actual device - } - dsyslog("creating cDvbDevice"); - new cDvbDevice(Adapter); // it's a "budget" device return true; } else if (errno != ENODEV && errno != EINVAL) @@ -472,26 +468,49 @@ bool cDvbDevice::Probe(int Adapter) return false; } +bool cDvbDevice::Probe(int Adapter, int Frontend) +{ + cString FileName = DvbName(DEV_DVB_FRONTEND, Adapter, Frontend); + dsyslog("probing %s", *FileName); + for (cDvbDeviceProbe *dp = DvbDeviceProbes.First(); dp; dp = DvbDeviceProbes.Next(dp)) { + if (dp->Probe(Adapter, Frontend)) + return true; // a plugin has created the actual device + } + dsyslog("creating cDvbDevice"); + new cDvbDevice(Adapter, Frontend); // it's a "budget" device + return true; +} + bool cDvbDevice::Initialize(void) { - int found = 0; - int i; - for (i = 0; i < MAXDVBDEVICES; i++) { - if (UseDevice(NextCardIndex())) { - if (Probe(i)) - found++; - else - break; - } - else - NextCardIndex(1); // skips this one + 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: ; } - NextCardIndex(MAXDVBDEVICES - i); // skips the rest - if (found > 0) - isyslog("found %d video device%s", found, found > 1 ? "s" : ""); +LastAdapter: + NextCardIndex(MAXDVBDEVICES - Checked); // skips the rest + if (Found > 0) + isyslog("found %d DVB device%s", Found, Found > 1 ? "s" : ""); else isyslog("no DVB device found"); - return found > 0; + return Found > 0; } bool cDvbDevice::Ready(void) @@ -513,7 +532,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, CardIndex(), O_RDWR | O_NONBLOCK, true); + Handle->handle = DvbOpen(DEV_DVB_DEMUX, adapter, frontend, O_RDWR | O_NONBLOCK, true); if (Handle->handle < 0) { LOG_ERROR; return false; @@ -548,7 +567,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, CardIndex()); + cString FileName = DvbName(DEV_DVB_DEMUX, adapter, frontend); int f = open(FileName, O_RDWR | O_NONBLOCK); if (f >= 0) { dmx_sct_filter_params sctFilterParams; @@ -658,7 +677,7 @@ void cDvbDevice::SetTransferModeForDolbyDigital(int Mode) bool cDvbDevice::OpenDvr(void) { CloseDvr(); - fd_dvr = DvbOpen(DEV_DVB_DVR, CardIndex(), O_RDONLY | O_NONBLOCK, true); + fd_dvr = DvbOpen(DEV_DVB_DVR, adapter, frontend, 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 c0faa35e..b6cc950a 100644 --- a/dvbdevice.h +++ b/dvbdevice.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: dvbdevice.h 2.10 2009/12/31 15:38:05 kls Exp $ + * $Id: dvbdevice.h 2.11 2010/01/04 14:07:12 kls Exp $ */ #ifndef __DVBDEVICE_H @@ -37,23 +37,27 @@ class cDvbTuner; class cDvbDevice : public cDevice { protected: - static cString DvbName(const char *Name, int n); - static int DvbOpen(const char *Name, int n, int Mode, bool ReportError = false); + 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 Probe(int Adapter); + static bool Exists(int Adapter, int Frontend); + ///< Checks whether the given adapter/frontend exists. + static bool Probe(int Adapter, int Frontend); ///< Probes for existing DVB devices. public: static bool Initialize(void); ///< Initializes the DVB devices. ///< Must be called before accessing any DVB functions. ///< \return True if any devices are available. +protected: + int adapter, frontend; private: dvb_frontend_info frontendInfo; int numProvidedSystems; fe_delivery_system frontendType; int fd_dvr, fd_ca; public: - cDvbDevice(int n); + cDvbDevice(int Adapter, int Frontend); virtual ~cDvbDevice(); virtual bool Ready(void); @@ -125,7 +129,7 @@ class cDvbDeviceProbe : public cListObject { public: cDvbDeviceProbe(void); virtual ~cDvbDeviceProbe(); - virtual bool Probe(int Adapter) = 0; + virtual bool Probe(int Adapter, int Frontend) = 0; ///< Probes for a DVB device at the given Adapter and creates the appropriate ///< object derived from cDvbDevice if applicable. ///< Returns true if a device has been created. -- cgit v1.2.3