diff --git a/CONTRIBUTORS b/CONTRIBUTORS index ae550b81..a6663d9a 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -446,6 +446,7 @@ Oliver Endriss Reinhard Walter Buchner for adding some satellites to 'sources.conf' for his help in testing tuning with "Motor-DiSEqC" + for his help in debugging CAM support Lauri Tischler for helping to test and debug the new channel source and DiSEqC handling diff --git a/HISTORY b/HISTORY index 8e770ee7..161f054e 100644 --- a/HISTORY +++ b/HISTORY @@ -1947,3 +1947,9 @@ Video Disk Recorder Revision History - Fixed a new/delete malloc/free mismatch in ringbuffer.c (thanks to Stefan Huelswitt for reporting this one). - Improved CAM handling. + +2003-02-09: Version 1.1.24 + +- Improved CAM handling (thanks to Reinhard Walter Buchner for a great deal of help + in debugging this). It is now possible to insert the CAM in any of the two slots, + to insert and remove it while VDR is running and even to have two CAMs inserted. diff --git a/ci.c b/ci.c index 97de9b01..f99be7d4 100644 --- a/ci.c +++ b/ci.c @@ -4,15 +4,11 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.c 1.3 2003/02/02 15:49:52 kls Exp $ + * $Id: ci.c 1.4 2003/02/09 11:54:22 kls Exp $ */ /* XXX TODO -- handle slots separately -- use return values - update CA descriptors in case they change -- dynamically react on CAM insert/remove -- implement CAM reset (per slot) XXX*/ #include "ci.h" @@ -215,7 +211,7 @@ int cTPDU::Write(int fd) int cTPDU::Read(int fd) { - size = read(fd, data, sizeof(data)); + size = safe_read(fd, data, sizeof(data)); if (size < 0) { esyslog("ERROR: %m"); size = 0; @@ -229,15 +225,15 @@ void cTPDU::Dump(bool Outgoing) { if (DumpTPDUDataTransfer) { #define MAX_DUMP 256 - printf("%s ", Outgoing ? "-->" : "<--"); + fprintf(stderr, "%s ", Outgoing ? "-->" : "<--"); for (int i = 0; i < size && i < MAX_DUMP; i++) - printf("%02X ", data[i]); - printf("%s\n", size >= MAX_DUMP ? "..." : ""); + fprintf(stderr, "%02X ", data[i]); + fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : ""); if (!Outgoing) { - printf(" "); + fprintf(stderr, " "); for (int i = 0; i < size && i < MAX_DUMP; i++) - printf("%2c ", isprint(data[i]) ? data[i] : '.'); - printf("%s\n", size >= MAX_DUMP ? "..." : ""); + fprintf(stderr, "%2c ", isprint(data[i]) ? data[i] : '.'); + fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : ""); } } } @@ -288,6 +284,7 @@ private: public: cCiTransportConnection(void); ~cCiTransportConnection(); + int Slot(void) const { return slot; } int SendData(int Length, const uint8_t *Data); int RecvData(void); const uint8_t *Data(int &Length); @@ -324,15 +321,15 @@ int cCiTransportConnection::SendTPDU(uint8_t Tag, int Length, const uint8_t *Dat return TPDU.Write(fd); } +#define CAM_READ_TIMEOUT 3500 // ms + int cCiTransportConnection::RecvTPDU(void) { - //XXX poll, timeout??? struct pollfd pfd[1]; pfd[0].fd = fd; pfd[0].events = POLLIN; lastResponse = ERROR; - if (poll(pfd, 1, 3500/*XXX*/) && (pfd[0].revents & POLLIN))//XXX - if (tpdu->Read(fd) == OK && tpdu->Tcid() == tcid) { + if (poll(pfd, 1, CAM_READ_TIMEOUT) && (pfd[0].revents & POLLIN) && tpdu->Read(fd) == OK && tpdu->Tcid() == tcid) { switch (state) { case stIDLE: break; case stCREATION: if (tpdu->Tag() == T_CTC_REPLY) { @@ -363,6 +360,10 @@ int cCiTransportConnection::RecvTPDU(void) break; } } + else { + esyslog("ERROR: CAM: Read failed: slot %d, tcid %d\n", slot, tcid); + Init(-1, slot, tcid); + } return lastResponse; } @@ -385,11 +386,8 @@ int cCiTransportConnection::SendData(int Length, const uint8_t *Data) int cCiTransportConnection::RecvData(void) { - if (SendTPDU(T_RCV) == OK) { - if (RecvTPDU() == OK) { - //XXX - } - } + if (SendTPDU(T_RCV) == OK) + return RecvTPDU(); return ERROR; } @@ -403,7 +401,18 @@ int cCiTransportConnection::CreateConnection(void) if (state == stIDLE) { if (SendTPDU(T_CREATE_TC) == OK) { state = stCREATION; - return OK; + if (RecvTPDU() == T_CTC_REPLY) + return OK; + // the following is a workaround for CAMs that don't quite follow the specs... + else { + dbgprotocol("*** no reaction on T_CREATE_TC - retrying\n"); + if (RecvTPDU() == T_CTC_REPLY) { + dbgprotocol("*** received T_CTC_REPLY\n"); + RecvTPDU(); + dbgprotocol("*** done dummy RecvTPDU()\n"); + } + return OK; + } } } return ERROR; @@ -412,9 +421,8 @@ int cCiTransportConnection::CreateConnection(void) int cCiTransportConnection::Poll(void) { if (state == stACTIVE) { - if (SendTPDU(T_DATA_LAST) == OK) { + if (SendTPDU(T_DATA_LAST) == OK) return RecvTPDU(); - } } return ERROR; } @@ -428,11 +436,12 @@ private: int fd; int numSlots; cCiTransportConnection tc[MAX_CI_CONNECT]; - bool ResetSlot(int Slot); public: cCiTransportLayer(int Fd, int NumSlots); - cCiTransportConnection *NewConnection(void); - int Process(void); + cCiTransportConnection *NewConnection(int Slot); + bool ResetSlot(int Slot); + bool ModuleReady(int Slot); + cCiTransportConnection *Process(int Slot); }; cCiTransportLayer::cCiTransportLayer(int Fd, int NumSlots) @@ -441,46 +450,28 @@ cCiTransportLayer::cCiTransportLayer(int Fd, int NumSlots) numSlots = NumSlots; for (int s = 0; s < numSlots; s++) ResetSlot(s); - for (int i = 0; i < MAX_CI_CONNECT; i++) - tc[i].Init(fd, 0/*XXX*/, i + 1); } -cCiTransportConnection *cCiTransportLayer::NewConnection(void) +cCiTransportConnection *cCiTransportLayer::NewConnection(int Slot) { for (int i = 0; i < MAX_CI_CONNECT; i++) { if (tc[i].State() == stIDLE) { - if (tc[i].CreateConnection() == OK) { - if (tc[i].RecvTPDU() == T_CTC_REPLY) - return &tc[i]; - } + dbgprotocol("Creating connection: slot %d, tcid %d\n", Slot, i + 1); + tc[i].Init(fd, Slot, i + 1); + if (tc[i].CreateConnection() == OK) + return &tc[i]; break; } } return NULL; } -#define CA_RESET_TIMEOUT 3 // seconds - bool cCiTransportLayer::ResetSlot(int Slot) { dbgprotocol("Resetting slot %d...", Slot); - ca_slot_info_t sinfo; - sinfo.num = Slot; if (ioctl(fd, CA_RESET, 1 << Slot) != -1) { - time_t t0 = time(NULL); - do { - if (ioctl(fd, CA_GET_SLOT_INFO, &sinfo) != -1) { - ioctl(fd, CA_GET_SLOT_INFO, &sinfo); - if ((sinfo.flags & CA_CI_MODULE_READY) != 0) { - dbgprotocol("ok.\n"); - return true; - } - } - else { - esyslog("ERROR: can't get info on CAM slot %d: %m", Slot); - break; - } - } while (time(NULL) - t0 < CA_RESET_TIMEOUT); + dbgprotocol("ok.\n"); + return true; } else esyslog("ERROR: can't reset CAM slot %d: %m", Slot); @@ -488,35 +479,55 @@ bool cCiTransportLayer::ResetSlot(int Slot) return false; } -int cCiTransportLayer::Process(void) +bool cCiTransportLayer::ModuleReady(int Slot) +{ + ca_slot_info_t sinfo; + sinfo.num = Slot; + if (ioctl(fd, CA_GET_SLOT_INFO, &sinfo) != -1) + return sinfo.flags & CA_CI_MODULE_READY; + else + esyslog("ERROR: can't get info on CAM slot %d: %m", Slot); + return false; +} + +cCiTransportConnection *cCiTransportLayer::Process(int Slot) { for (int i = 0; i < MAX_CI_CONNECT; i++) { cCiTransportConnection *Tc = &tc[i]; - if (Tc->State() == stACTIVE) { - if (!Tc->DataAvailable()) { - if (Tc->Poll() != OK) - ;//XXX continue; - } - switch (Tc->LastResponse()) { - case T_REQUEST_TC: - //XXX - break; - case T_DATA_MORE: - case T_DATA_LAST: - case T_CTC_REPLY: - case T_SB: - if (Tc->DataAvailable()) - Tc->RecvData(); - break; - case TIMEOUT: - case ERROR: - default: - //XXX Tc->state = stIDLE;//XXX Init()??? + if (Tc->Slot() == Slot) { + switch (Tc->State()) { + case stCREATION: + case stACTIVE: + if (!Tc->DataAvailable()) { + if (Tc->Poll() != OK) + ;//XXX continue; + } + switch (Tc->LastResponse()) { + case T_REQUEST_TC: + //XXX + break; + case T_DATA_MORE: + case T_DATA_LAST: + case T_CTC_REPLY: + case T_SB: + if (Tc->DataAvailable()) + Tc->RecvData(); + break; + case TIMEOUT: + case ERROR: + default: + //XXX Tc->state = stIDLE;//XXX Init()??? + return NULL; + break; + } + //XXX this will only work with _one_ transport connection per slot! + return Tc; break; + default: ; } } } - return OK; + return NULL; } // -- cCiSession ------------------------------------------------------------- @@ -608,6 +619,7 @@ protected: public: cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc); virtual ~cCiSession(); + const cCiTransportConnection *Tc(void) { return tc; } int SessionId(void) { return sessionId; } int ResourceId(void) { return resourceId; } virtual bool Process(int Length = 0, const uint8_t *Data = NULL); @@ -1261,9 +1273,7 @@ cCiHandler::cCiHandler(int Fd, int NumSlots) for (int i = 0; i < MAX_CI_SESSION; i++) sessions[i] = NULL; tpl = new cCiTransportLayer(Fd, numSlots); - tc = tpl->NewConnection(); - if (!tc) - isyslog("CAM: no CAM detected"); + tc = NULL; } cCiHandler::~cCiHandler() @@ -1281,14 +1291,9 @@ cCiHandler *cCiHandler::CreateCiHandler(const char *FileName) if (ioctl(fd_ca, CA_GET_CAP, &Caps) == 0) { int NumSlots = Caps.slot_num; if (NumSlots > 0) { - dsyslog("CAM: found %d CAM slots", NumSlots); - if (Caps.slot_type == CA_CI_LINK) { - cCiHandler *CiHandler = new cCiHandler(fd_ca, NumSlots); - // drive the initial data exchange: - for (int i = 0; i < 20; i++) //XXX make this dynamic??? - CiHandler->Process(); - return CiHandler; - } + //XXX dsyslog("CAM: found %d CAM slots", NumSlots); // TODO let's do this only once we can be sure that there _really_ is a CAM adapter! + if (Caps.slot_type == CA_CI_LINK) + return new cCiHandler(fd_ca, NumSlots); else esyslog("ERROR: CAM doesn't support link layer interface"); } @@ -1320,7 +1325,7 @@ bool cCiHandler::Send(uint8_t Tag, int SessionId, int ResourceId, int Status) *(short *)p = htons(SessionId); p += 2; buffer[1] = p - buffer - 2; // length - return tc->SendData(p - buffer, buffer) == OK; + return tc && tc->SendData(p - buffer, buffer) == OK; } cCiSession *cCiHandler::GetSessionBySessionId(int SessionId) @@ -1332,10 +1337,10 @@ cCiSession *cCiHandler::GetSessionBySessionId(int SessionId) return NULL; } -cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId) +cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId, int Slot) { for (int i = 0; i < MAX_CI_SESSION; i++) { - if (sessions[i] && sessions[i]->ResourceId() == ResourceId) + if (sessions[i] && sessions[i]->Tc()->Slot() == Slot && sessions[i]->ResourceId() == ResourceId) return sessions[i]; } return NULL; @@ -1343,7 +1348,7 @@ cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId) cCiSession *cCiHandler::CreateSession(int ResourceId) { - if (!GetSessionByResourceId(ResourceId)) { + if (!GetSessionByResourceId(ResourceId, tc->Slot())) { for (int i = 0; i < MAX_CI_SESSION; i++) { if (!sessions[i]) { switch (ResourceId) { @@ -1403,81 +1408,107 @@ bool cCiHandler::CloseSession(int SessionId) return false; } -bool cCiHandler::Process(void) +int cCiHandler::CloseAllSessions(int Slot) { - if (tc) { - cMutexLock MutexLock(&mutex); - if (tpl->Process() == OK) { - int Length; - const uint8_t *Data = tc->Data(Length); - if (Data && Length > 1) { - switch (*Data) { - case ST_SESSION_NUMBER: if (Length > 4) { - int SessionId = ntohs(*(short *)&Data[2]); - cCiSession *Session = GetSessionBySessionId(SessionId); - if (Session) - return Session->Process(Length - 4, Data + 4); - else { - esyslog("ERROR: unknown session id: %d", SessionId); - return false; - } - } - break; - case ST_OPEN_SESSION_REQUEST: return OpenSession(Length, Data); - case ST_CLOSE_SESSION_REQUEST: if (Length == 4) - return CloseSession(ntohs(*(short *)&Data[2])); - break; - case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default - case ST_CLOSE_SESSION_RESPONSE: //XXX fall through to default - default: esyslog("ERROR: unknown session tag: %02X", *Data); - return false; - } - return true; - } - for (int i = 0; i < MAX_CI_SESSION; i++) { - if (sessions[i]) - sessions[i]->Process();//XXX retval??? - } - } - } - return false; + int result = 0; + for (int i = 0; i < MAX_CI_SESSION; i++) { + if (sessions[i] && sessions[i]->Tc()->Slot() == Slot) { + CloseSession(sessions[i]->SessionId()); + result++; + } + } + return result; } -bool cCiHandler::EnterMenu(void) +void cCiHandler::Process(void) { cMutexLock MutexLock(&mutex); - //XXX slots??? - cCiApplicationInformation *api = (cCiApplicationInformation *)GetSessionByResourceId(RI_APPLICATION_INFORMATION); + for (int Slot = 0; Slot < numSlots; Slot++) { + tc = tpl->Process(Slot); + if (tc) { + int Length; + const uint8_t *Data = tc->Data(Length); + if (Data && Length > 1) { + switch (*Data) { + case ST_SESSION_NUMBER: if (Length > 4) { + int SessionId = ntohs(*(short *)&Data[2]); + cCiSession *Session = GetSessionBySessionId(SessionId); + if (Session) + Session->Process(Length - 4, Data + 4); + else + esyslog("ERROR: unknown session id: %d", SessionId); + } + break; + case ST_OPEN_SESSION_REQUEST: OpenSession(Length, Data); + break; + case ST_CLOSE_SESSION_REQUEST: if (Length == 4) + CloseSession(ntohs(*(short *)&Data[2])); + break; + case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default + case ST_CLOSE_SESSION_RESPONSE: //XXX fall through to default + default: esyslog("ERROR: unknown session tag: %02X", *Data); + } + } + } + else { + if (!CloseAllSessions(Slot)) { + if (tpl->ModuleReady(Slot)) { + dbgprotocol("Module ready in slot %d\n", Slot); + tpl->NewConnection(Slot); + } + } + } + } + for (int i = 0; i < MAX_CI_SESSION; i++) { + if (sessions[i]) + sessions[i]->Process(); + } +} + +bool cCiHandler::EnterMenu(int Slot) +{ + cMutexLock MutexLock(&mutex); + cCiApplicationInformation *api = (cCiApplicationInformation *)GetSessionByResourceId(RI_APPLICATION_INFORMATION, Slot); return api ? api->EnterMenu() : false; } cCiMenu *cCiHandler::GetMenu(void) { cMutexLock MutexLock(&mutex); - //XXX slots??? - cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI); - return mmi ? mmi->Menu() : NULL; + for (int Slot = 0; Slot < numSlots; Slot++) { + cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI, Slot); + if (mmi) + return mmi->Menu(); + } + return NULL; } cCiEnquiry *cCiHandler::GetEnquiry(void) { cMutexLock MutexLock(&mutex); - //XXX slots??? - cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI); - return mmi ? mmi->Enquiry() : NULL; + for (int Slot = 0; Slot < numSlots; Slot++) { + cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI, Slot); + if (mmi) + return mmi->Enquiry(); + } + return NULL; } bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt) { cMutexLock MutexLock(&mutex); - //XXX slots??? - cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT); - return cas ? cas->SendPMT(CaPmt) : false; + bool result = false; + for (int Slot = 0; Slot < numSlots; Slot++) { + cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT, Slot); + if (cas) + result |= cas->SendPMT(CaPmt); + } + return result; } -bool cCiHandler::Reset(void) +bool cCiHandler::Reset(int Slot) { cMutexLock MutexLock(&mutex); - //XXX slots??? - return false;//XXX not yet implemented + CloseAllSessions(Slot); + return tpl->ResetSlot(Slot); } diff --git a/ci.h b/ci.h index c9cd6f54..5d33b611 100644 --- a/ci.h +++ b/ci.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: ci.h 1.1 2003/01/06 12:31:09 kls Exp $ + * $Id: ci.h 1.2 2003/02/09 11:44:00 kls Exp $ */ #ifndef __CI_H @@ -86,20 +86,21 @@ private: int ResourceIdToInt(const uint8_t *Data); bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1); cCiSession *GetSessionBySessionId(int SessionId); - cCiSession *GetSessionByResourceId(int ResourceId); + cCiSession *GetSessionByResourceId(int ResourceId, int Slot); cCiSession *CreateSession(int ResourceId); bool OpenSession(int Length, const uint8_t *Data); bool CloseSession(int SessionId); + int CloseAllSessions(int Slot); cCiHandler(int Fd, int NumSlots); public: ~cCiHandler(); static cCiHandler *CreateCiHandler(const char *FileName); - bool Process(void); - bool EnterMenu(void); + void Process(void); + bool EnterMenu(int Slot); cCiMenu *GetMenu(void); cCiEnquiry *GetEnquiry(void); bool SetCaPmt(cCiCaPmt &CaPmt); - bool Reset(void); + bool Reset(int Slot); }; #endif //__CI_H diff --git a/config.h b/config.h index 8bf33f62..1760eed9 100644 --- a/config.h +++ b/config.h @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: config.h 1.147 2003/01/26 19:50:19 kls Exp $ + * $Id: config.h 1.148 2003/02/08 10:25:44 kls Exp $ */ #ifndef __CONFIG_H @@ -19,7 +19,7 @@ #include "device.h" #include "tools.h" -#define VDRVERSION "1.1.23" +#define VDRVERSION "1.1.24" #define MAXPRIORITY 99 #define MAXLIFETIME 99 diff --git a/dvbdevice.c b/dvbdevice.c index 1ffe067a..01d828fa 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 1.42 2003/02/02 15:31:31 kls Exp $ + * $Id: dvbdevice.c 1.43 2003/02/09 11:47:02 kls Exp $ */ #include "dvbdevice.h" @@ -238,6 +238,7 @@ bool cDvbTuner::SetFrontend(void) void cDvbTuner::Action(void) { + time_t StartTime = time(NULL); dsyslog("tuner thread started on device %d (pid=%d)", cardIndex + 1, getpid()); active = true; while (active) { @@ -258,24 +259,28 @@ void cDvbTuner::Action(void) continue; } } - if (ciHandler && !caSet) {//XXX TODO update in case the CA descriptors have changed - uchar buffer[2048]; - int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer); - if (length > 0) { - cCiCaPmt CaPmt(channel.Sid()); - CaPmt.AddCaDescriptor(length, buffer); - if (channel.Vpid()) - CaPmt.AddPid(channel.Vpid()); - if (channel.Apid1()) - CaPmt.AddPid(channel.Apid1()); - if (channel.Apid2()) - CaPmt.AddPid(channel.Apid2()); - if (channel.Dpid1()) - CaPmt.AddPid(channel.Dpid1()); - caSet = ciHandler->SetCaPmt(CaPmt); + if (ciHandler) { + ciHandler->Process(); + if (!caSet) {//XXX TODO update in case the CA descriptors have changed + uchar buffer[2048]; + int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer); + if (length > 0) { + cCiCaPmt CaPmt(channel.Sid()); + CaPmt.AddCaDescriptor(length, buffer); + if (channel.Vpid()) + CaPmt.AddPid(channel.Vpid()); + if (channel.Apid1()) + CaPmt.AddPid(channel.Apid1()); + if (channel.Apid2()) + CaPmt.AddPid(channel.Apid2()); + if (channel.Dpid1()) + CaPmt.AddPid(channel.Dpid1()); + caSet = ciHandler->SetCaPmt(CaPmt); + } } } - newSet.TimedWait(mutex, 1000); + // in the beginning we loop more often to let the CAM connection start up fast + newSet.TimedWait(mutex, (ciHandler && (time(NULL) - StartTime < 20)) ? 100 : 1000); } dsyslog("tuner thread ended on device %d (pid=%d)", cardIndex + 1, getpid()); } diff --git a/menu.c b/menu.c index 081a4ba1..495cb6a3 100644 --- a/menu.c +++ b/menu.c @@ -4,7 +4,7 @@ * See the main source file 'vdr.c' for copyright information and * how to reach the author. * - * $Id: menu.c 1.232 2003/01/19 14:59:46 kls Exp $ + * $Id: menu.c 1.233 2003/02/09 10:46:25 kls Exp $ */ #include "menu.h" @@ -1537,6 +1537,7 @@ cMenuCam::cMenuCam(cCiMenu *CiMenu) Add(new cOsdItem(ciMenu->SubTitleText())); Add(new cOsdItem(ciMenu->BottomText())); Display(); + dsyslog("CAM: Menu - %s", ciMenu->TitleText()); } cMenuCam::~cMenuCam() @@ -1622,7 +1623,6 @@ cOsdObject *CamControl(void) if (Device) { cCiHandler *CiHandler = Device->CiHandler(); if (CiHandler) { - CiHandler->Process(); cCiMenu *CiMenu = CiHandler->GetMenu(); if (CiMenu) return new cMenuCam(CiMenu); @@ -2069,7 +2069,7 @@ class cMenuSetupCICAM : public cMenuSetupBase { private: int helpKeys; void SetHelpKeys(void); - cCiHandler *GetCurrentCiHandler(void); + cCiHandler *GetCurrentCiHandler(int *Slot = NULL); eOSState Menu(void); eOSState Reset(void); public: @@ -2091,9 +2091,11 @@ cMenuSetupCICAM::cMenuSetupCICAM(void) SetHelpKeys(); } -cCiHandler *cMenuSetupCICAM::GetCurrentCiHandler(void) +cCiHandler *cMenuSetupCICAM::GetCurrentCiHandler(int *Slot) { cDevice *Device = cDevice::GetDevice(Current() / 2); + if (Slot) + *Slot = Current() % 2; return Device ? Device->CiHandler() : NULL; } @@ -2112,8 +2114,9 @@ void cMenuSetupCICAM::SetHelpKeys(void) eOSState cMenuSetupCICAM::Menu(void) { - cCiHandler *CiHandler = GetCurrentCiHandler(); - if (CiHandler && CiHandler->EnterMenu()) + int Slot = 0; + cCiHandler *CiHandler = GetCurrentCiHandler(&Slot); + if (CiHandler && CiHandler->EnterMenu(Slot)) return osEnd; // the CAM menu will be executed explicitly from the main loop else Interface->Error(tr("Can't open CAM menu!")); @@ -2122,9 +2125,12 @@ eOSState cMenuSetupCICAM::Menu(void) eOSState cMenuSetupCICAM::Reset(void) { - cCiHandler *CiHandler = GetCurrentCiHandler(); - if (CiHandler && CiHandler->Reset()) + int Slot = 0; + cCiHandler *CiHandler = GetCurrentCiHandler(&Slot); + if (CiHandler && CiHandler->Reset(Slot)) { Interface->Info(tr("CAM has been reset")); + return osEnd; + } else Interface->Error(tr("Can't reset CAM!")); return osContinue; diff --git a/vdr.c b/vdr.c index 87550ded..166afb04 100644 --- a/vdr.c +++ b/vdr.c @@ -22,7 +22,7 @@ * * The project's page is at http://www.cadsoft.de/people/kls/vdr * - * $Id: vdr.c 1.141 2003/01/26 11:56:31 kls Exp $ + * $Id: vdr.c 1.142 2003/02/09 11:25:38 kls Exp $ */ #include @@ -469,7 +469,7 @@ int main(int argc, char *argv[]) } } // CAM control: - if (!Menu) + if (!Interface->IsOpen()) Menu = CamControl(); // User Input: cOsdObject *Interact = Menu ? Menu : cControl::Control();