diff -u -N -r vdr_1.4.5_orig/device.c vdr_1.4.5_eddi/device.c --- vdr_1.4.5_orig/device.c 2006-09-03 12:13:25.000000000 +0200 +++ vdr_1.4.5_eddi/device.c 2007-02-08 00:16:56.000000000 +0100 @@ -143,13 +143,19 @@ int cDevice::numDevices = 0; int cDevice::useDevice = 0; int cDevice::nextCardIndex = 0; +int cDevice::forceCardIndex = -1; int cDevice::currentChannel = 1; cDevice *cDevice::device[MAXDEVICES] = { NULL }; cDevice *cDevice::primaryDevice = NULL; cDevice::cDevice(void) { - cardIndex = nextCardIndex++; + esyslog("cDevice Constructor"); + + if (forceCardIndex >=0) + cardIndex = forceCardIndex; + else + cardIndex = nextCardIndex++; SetDescription("receiver on device %d", CardIndex() + 1); @@ -174,14 +180,20 @@ for (int i = 0; i < MAXRECEIVERS; i++) receiver[i] = NULL; - if (numDevices < MAXDEVICES) - device[numDevices++] = this; - else - esyslog("ERROR: too many devices!"); + if (forceCardIndex >=0) + device[cardIndex] = this; + else { + if (numDevices < MAXDEVICES) + device[numDevices++] = this; + else + esyslog("ERROR: too many devices!"); + } + esyslog("cDevice Constructor: cardIndex=%d", cardIndex); } cDevice::~cDevice() { + esyslog("cDevice Destructor"); Detach(player); for (int i = 0; i < MAXRECEIVERS; i++) Detach(receiver[i]); @@ -192,6 +204,7 @@ delete eitFilter; delete sectionHandler; delete pesAssembler; + esyslog("cDevice Destructor: cardIndex=%d", cardIndex); } bool cDevice::WaitForAllDevicesReady(int Timeout) diff -u -N -r vdr_1.4.5_orig/device.h vdr_1.4.5_eddi/device.h --- vdr_1.4.5_orig/device.h 2006-06-15 11:32:48.000000000 +0200 +++ vdr_1.4.5_eddi/device.h 2007-02-08 00:24:59.000000000 +0100 @@ -139,6 +139,7 @@ ///< Must be called at the end of the program. private: static int nextCardIndex; + static int forceCardIndex; int cardIndex; protected: cDevice(void); @@ -167,6 +168,7 @@ ///< device (On = false), it should do so in this function. public: bool IsPrimaryDevice(void) const { return this == primaryDevice; } + void ForceCardIndex(int n) const { forceCardIndex = n; } int CardIndex(void) const { return cardIndex; } ///< Returns the card index of this device (0 ... MAXDEVICES - 1). int DeviceNumber(void) const; diff -u -N -r vdr_1.4.5_orig/dvbdevice.c vdr_1.4.5_eddi/dvbdevice.c --- vdr_1.4.5_orig/dvbdevice.c 2006-08-14 11:38:32.000000000 +0200 +++ vdr_1.4.5_eddi/dvbdevice.c 2007-02-08 01:06:13.000000000 +0100 @@ -47,22 +47,25 @@ #define DVBT_TUNE_TIMEOUT 9000 //ms #define DVBT_LOCK_TIMEOUT 2000 //ms +cDvbDevice *dvbDevice[MAXDVBFRONTENDS] = { NULL }; + class cDvbName { private: char buffer[PATH_MAX]; public: - cDvbName(const char *Name, int n) { - snprintf(buffer, sizeof(buffer), "%s%d/%s%d", DEV_DVB_ADAPTER, n, Name, 0); + cDvbName(const char *Name, int adapter, int frontend) { + snprintf(buffer, sizeof(buffer), "%s%d/%s%d", DEV_DVB_ADAPTER, adapter, Name, frontend); } const char *operator*() { return buffer; } }; -static int DvbOpen(const char *Name, int n, int Mode, bool ReportError = false) +static int DvbOpen(const char *Name, int adapter, int frontend, int Mode, bool ReportError = false) { - const char *FileName = *cDvbName(Name, n); + const char *FileName = *cDvbName(Name, adapter, frontend); int fd = open(FileName, Mode); if (fd < 0 && ReportError) LOG_ERROR_STR(FileName); + esyslog("DvbOpen: %s", FileName); return fd; } @@ -358,7 +361,7 @@ int cDvbDevice::devVideoOffset = -1; int cDvbDevice::setTransferModeForDolbyDigital = 1; -cDvbDevice::cDvbDevice(int n) +cDvbDevice::cDvbDevice(int adapter, int frontend) { dvbTuner = NULL; frontendType = fe_type_t(-1); // don't know how else to initialize this - there is no FE_UNKNOWN @@ -368,14 +371,14 @@ // Devices that are present on all card types: - int fd_frontend = DvbOpen(DEV_DVB_FRONTEND, n, O_RDWR | O_NONBLOCK); + fd_frontend = DvbOpen(DEV_DVB_FRONTEND, adapter, frontend, O_RDWR | O_NONBLOCK); // 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 DVR device (will be opened and closed as needed): @@ -420,59 +423,83 @@ dvb_frontend_info feinfo; if (ioctl(fd_frontend, FE_GET_INFO, &feinfo) >= 0) { frontendType = feinfo.type; - ciHandler = cCiHandler::CreateCiHandler(*cDvbName(DEV_DVB_CA, n)); + ciHandler = cCiHandler::CreateCiHandler(*cDvbName(DEV_DVB_CA, adapter, frontend)); + esyslog("cDvbDevice: CardIndex=%d", CardIndex()); dvbTuner = new cDvbTuner(fd_frontend, CardIndex(), frontendType, ciHandler); } else LOG_ERROR; } else - esyslog("ERROR: can't open DVB device %d", n); + esyslog("ERROR: can't open DVB adapter %d - frontend %d", adapter, frontend); StartSectionHandler(); } cDvbDevice::~cDvbDevice() { + esyslog("~cDvbDevice()"); delete spuDecoder; delete dvbTuner; + close(fd_stc); + close(fd_audio); + close(fd_video); + close(fd_osd); + close(fd_frontend); // We're not explicitly closing any device files here, since this sometimes // caused segfaults. Besides, the program is about to terminate anyway... } -bool cDvbDevice::Probe(const char *FileName) +int cDvbDevice::Probe(const char *FileName) { if (access(FileName, F_OK) == 0) { dsyslog("probing %s", FileName); int f = open(FileName, O_RDONLY); if (f >= 0) { close(f); - return true; } else if (errno != ENODEV && errno != EINVAL) LOG_ERROR_STR(FileName); } else if (errno != ENOENT) LOG_ERROR_STR(FileName); - return false; + return errno; } bool cDvbDevice::Initialize(void) { int found = 0; - int i; + int i, j, rc = 0; for (i = 0; i < MAXDVBDEVICES; i++) { + j = 0; + while (rc != ENOENT) { if (UseDevice(NextCardIndex())) { - if (Probe(*cDvbName(DEV_DVB_FRONTEND, i))) { - new cDvbDevice(i); - found++; - } - else - break; + rc = Probe(*cDvbName(DEV_DVB_FRONTEND, i ,j)); + switch (rc) { + case 0: dvbDevice[i] = new cDvbDevice(i,j); + dvbDevice[i]->SetNumFrontends(j); + dvbDevice[i]->SetCurFrontends(j); + found++; + break; + case EBUSY: // we have a frontend that can't work in shared mode + if (dvbDevice[i]) + dvbDevice[i]->SetNumFrontends(j); + esyslog("cDvbDevice::Initialize: WARNING %d - Device or resource busy", rc); + // we have a frontend that can't work in shared mode + break; + case ENOENT: esyslog("cDvbDevice::Initialize: Device %d have %d frontends", i, j); + break; + default: dvbDevice[i] = NULL; + esyslog("cDvbDevice::Initialize: %d", rc); + break; } + } else NextCardIndex(1); // skips this one - } + j++; + } + } + NextCardIndex(MAXDVBDEVICES - i); // skips the rest if (found > 0) isyslog("found %d video device%s", found, found > 1 ? "s" : ""); @@ -668,7 +695,8 @@ memset(&pesFilterParams, 0, sizeof(pesFilterParams)); if (On) { if (Handle->handle < 0) { - Handle->handle = DvbOpen(DEV_DVB_DEMUX, CardIndex(), O_RDWR | O_NONBLOCK, true); + esyslog("SetPid: CardIndex=%d", CardIndex()); + Handle->handle = DvbOpen(DEV_DVB_DEMUX, CardIndex(), dvbDevice[CardIndex()]->GetCurFrontends(), O_RDWR | O_NONBLOCK, true); if (Handle->handle < 0) { LOG_ERROR; return false; @@ -705,7 +733,7 @@ int cDvbDevice::OpenFilter(u_short Pid, u_char Tid, u_char Mask) { - const char *FileName = *cDvbName(DEV_DVB_DEMUX, CardIndex()); + const char *FileName = *cDvbName(DEV_DVB_DEMUX, CardIndex(), dvbDevice[CardIndex()]->GetCurFrontends()); int f = open(FileName, O_RDWR | O_NONBLOCK); if (f >= 0) { dmx_sct_filter_params sctFilterParams; @@ -769,6 +797,31 @@ bool result = false; bool hasPriority = Priority < 0 || Priority > this->Priority(); bool needsDetachReceivers = false; + int frontend = 0, maxfrontend = 0; + int adapter; + +//Todo: Add test to check if frontend is busy + + adapter = CardIndex(); + + maxfrontend = dvbDevice[adapter]->GetNumFrontends(); + + while (!result && frontend <= maxfrontend ) { + + esyslog("cDvbDevice::ProvidesChannel: frontend %d, maxfrontend %d, cardIndex %d", frontend, maxfrontend, adapter); + +// if (frontend != 0) { //wrong - should be frontend != GetCurFrontends(adapter) + + if (frontend != dvbDevice[adapter]->GetCurFrontends()) { + dvbDevice[adapter]->SetCurFrontends(frontend); + ForceCardIndex(adapter); + delete dvbDevice[adapter]; + dvbDevice[adapter] = NULL; + esyslog("cDvbDevice::ProvidesChannel stub: stop and restart frontend adapter/frontend %d/%d", adapter, frontend); + sleep(2); //dirty hack + dvbDevice[adapter] = new cDvbDevice(adapter, frontend); + ForceCardIndex(-1); + } if (ProvidesSource(Channel->Source()) && ProvidesCa(Channel)) { result = hasPriority; @@ -798,6 +851,11 @@ } if (NeedsDetachReceivers) *NeedsDetachReceivers = needsDetachReceivers; + + frontend++; + + } + return result; } @@ -836,7 +894,18 @@ // Set the tuner: +// cardindexbkp=CardIndex(); +// SetNextCardIndex(frontend+1); +// delete dvbDevice[CardIndex()]; +// dvbDevice[i]= NULL; +// if (frontend == 0) +// frontend = 1; +// else +// frontend = 0; +// esyslog("Allocating new cDvbDevice: Frontend %d, CardIndex %d", frontend, CardIndex()); +// dvbDevice[CardIndex()] = new cDvbDevice(CardIndex(), frontend); dvbTuner->Set(Channel, DoTune); +// SetNextCardIndex(cardindexbkp); // If this channel switch was requested by the EITScanner we don't wait for // a lock and don't set any live PIDs (the EITScanner will wait for the lock @@ -954,8 +1023,8 @@ { 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, CardIndex(), dvbDevice[CardIndex()]->GetCurFrontends(), O_RDWR | O_NONBLOCK); + fd_audio = DvbOpen(DEV_DVB_AUDIO, CardIndex(), dvbDevice[CardIndex()]->GetCurFrontends(), O_RDWR | O_NONBLOCK); SetVideoFormat(Setup.VideoFormat); } @@ -1183,7 +1252,7 @@ bool cDvbDevice::OpenDvr(void) { CloseDvr(); - fd_dvr = DvbOpen(DEV_DVB_DVR, CardIndex(), O_RDONLY | O_NONBLOCK, true); + fd_dvr = DvbOpen(DEV_DVB_DVR, CardIndex(), dvbDevice[CardIndex()]->GetCurFrontends(), O_RDONLY | O_NONBLOCK, true); if (fd_dvr >= 0) tsBuffer = new cTSBuffer(fd_dvr, MEGABYTE(2), CardIndex() + 1); return fd_dvr >= 0; diff -u -N -r vdr_1.4.5_orig/dvbdevice.h vdr_1.4.5_eddi/dvbdevice.h --- vdr_1.4.5_orig/dvbdevice.h 2006-05-28 17:05:19.000000000 +0200 +++ vdr_1.4.5_eddi/dvbdevice.h 2007-02-08 00:38:11.000000000 +0100 @@ -20,6 +20,7 @@ #endif #define MAXDVBDEVICES 4 +#define MAXDVBFRONTENDS 4 class cDvbTuner; @@ -27,7 +28,7 @@ class cDvbDevice : public cDevice { private: - static bool Probe(const char *FileName); + static int Probe(const char *FileName); ///< Probes for existing DVB devices. public: static bool Initialize(void); @@ -36,15 +37,20 @@ ///< \return True if any devices are available. private: fe_type_t frontendType; - int fd_osd, fd_audio, fd_video, fd_dvr, fd_stc; + int fd_frontend, fd_osd, fd_audio, fd_video, fd_dvr, fd_stc; + int numFrontends, curFrontends; protected: virtual void MakePrimaryDevice(bool On); public: - cDvbDevice(int n); + cDvbDevice(int adapter, int frontend); virtual ~cDvbDevice(); virtual bool Ready(void); virtual int ProvidesCa(const cChannel *Channel) const; virtual bool HasDecoder(void) const; + void SetNumFrontends(int n) { numFrontends = n; esyslog("SetNumFrontends: %d", numFrontends); } + int GetNumFrontends(void) const { esyslog("GetNumFrontends: %d", numFrontends); return numFrontends; } + void SetCurFrontends(int n) { curFrontends = n; esyslog("SetCurFrontends: %d", curFrontends); } + int GetCurFrontends(void) const { esyslog("GetCurFrontends: %d", curFrontends); return curFrontends; } // SPU facilities