1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Improved CAM support

This commit is contained in:
Klaus Schmidinger 2003-02-09 11:54:22 +01:00
parent b7777e230c
commit 777f330c77
8 changed files with 224 additions and 174 deletions

View File

@ -446,6 +446,7 @@ Oliver Endriss <o.endriss@gmx.de>
Reinhard Walter Buchner <rw.buchner@freenet.de> Reinhard Walter Buchner <rw.buchner@freenet.de>
for adding some satellites to 'sources.conf' for adding some satellites to 'sources.conf'
for his help in testing tuning with "Motor-DiSEqC" for his help in testing tuning with "Motor-DiSEqC"
for his help in debugging CAM support
Lauri Tischler <lauri.tischler@efore.fi> Lauri Tischler <lauri.tischler@efore.fi>
for helping to test and debug the new channel source and DiSEqC handling for helping to test and debug the new channel source and DiSEqC handling

View File

@ -1947,3 +1947,9 @@ Video Disk Recorder Revision History
- Fixed a new/delete malloc/free mismatch in ringbuffer.c (thanks to Stefan - Fixed a new/delete malloc/free mismatch in ringbuffer.c (thanks to Stefan
Huelswitt for reporting this one). Huelswitt for reporting this one).
- Improved CAM handling. - 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.

311
ci.c
View File

@ -4,15 +4,11 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 /* XXX TODO
- handle slots separately
- use return values
- update CA descriptors in case they change - update CA descriptors in case they change
- dynamically react on CAM insert/remove
- implement CAM reset (per slot)
XXX*/ XXX*/
#include "ci.h" #include "ci.h"
@ -215,7 +211,7 @@ int cTPDU::Write(int fd)
int cTPDU::Read(int fd) int cTPDU::Read(int fd)
{ {
size = read(fd, data, sizeof(data)); size = safe_read(fd, data, sizeof(data));
if (size < 0) { if (size < 0) {
esyslog("ERROR: %m"); esyslog("ERROR: %m");
size = 0; size = 0;
@ -229,15 +225,15 @@ void cTPDU::Dump(bool Outgoing)
{ {
if (DumpTPDUDataTransfer) { if (DumpTPDUDataTransfer) {
#define MAX_DUMP 256 #define MAX_DUMP 256
printf("%s ", Outgoing ? "-->" : "<--"); fprintf(stderr, "%s ", Outgoing ? "-->" : "<--");
for (int i = 0; i < size && i < MAX_DUMP; i++) for (int i = 0; i < size && i < MAX_DUMP; i++)
printf("%02X ", data[i]); fprintf(stderr, "%02X ", data[i]);
printf("%s\n", size >= MAX_DUMP ? "..." : ""); fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : "");
if (!Outgoing) { if (!Outgoing) {
printf(" "); fprintf(stderr, " ");
for (int i = 0; i < size && i < MAX_DUMP; i++) for (int i = 0; i < size && i < MAX_DUMP; i++)
printf("%2c ", isprint(data[i]) ? data[i] : '.'); fprintf(stderr, "%2c ", isprint(data[i]) ? data[i] : '.');
printf("%s\n", size >= MAX_DUMP ? "..." : ""); fprintf(stderr, "%s\n", size >= MAX_DUMP ? "..." : "");
} }
} }
} }
@ -288,6 +284,7 @@ private:
public: public:
cCiTransportConnection(void); cCiTransportConnection(void);
~cCiTransportConnection(); ~cCiTransportConnection();
int Slot(void) const { return slot; }
int SendData(int Length, const uint8_t *Data); int SendData(int Length, const uint8_t *Data);
int RecvData(void); int RecvData(void);
const uint8_t *Data(int &Length); 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); return TPDU.Write(fd);
} }
#define CAM_READ_TIMEOUT 3500 // ms
int cCiTransportConnection::RecvTPDU(void) int cCiTransportConnection::RecvTPDU(void)
{ {
//XXX poll, timeout???
struct pollfd pfd[1]; struct pollfd pfd[1];
pfd[0].fd = fd; pfd[0].fd = fd;
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
lastResponse = ERROR; lastResponse = ERROR;
if (poll(pfd, 1, 3500/*XXX*/) && (pfd[0].revents & POLLIN))//XXX if (poll(pfd, 1, CAM_READ_TIMEOUT) && (pfd[0].revents & POLLIN) && tpdu->Read(fd) == OK && tpdu->Tcid() == tcid) {
if (tpdu->Read(fd) == OK && tpdu->Tcid() == tcid) {
switch (state) { switch (state) {
case stIDLE: break; case stIDLE: break;
case stCREATION: if (tpdu->Tag() == T_CTC_REPLY) { case stCREATION: if (tpdu->Tag() == T_CTC_REPLY) {
@ -363,6 +360,10 @@ int cCiTransportConnection::RecvTPDU(void)
break; break;
} }
} }
else {
esyslog("ERROR: CAM: Read failed: slot %d, tcid %d\n", slot, tcid);
Init(-1, slot, tcid);
}
return lastResponse; return lastResponse;
} }
@ -385,11 +386,8 @@ int cCiTransportConnection::SendData(int Length, const uint8_t *Data)
int cCiTransportConnection::RecvData(void) int cCiTransportConnection::RecvData(void)
{ {
if (SendTPDU(T_RCV) == OK) { if (SendTPDU(T_RCV) == OK)
if (RecvTPDU() == OK) { return RecvTPDU();
//XXX
}
}
return ERROR; return ERROR;
} }
@ -403,7 +401,18 @@ int cCiTransportConnection::CreateConnection(void)
if (state == stIDLE) { if (state == stIDLE) {
if (SendTPDU(T_CREATE_TC) == OK) { if (SendTPDU(T_CREATE_TC) == OK) {
state = stCREATION; 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; return ERROR;
@ -412,9 +421,8 @@ int cCiTransportConnection::CreateConnection(void)
int cCiTransportConnection::Poll(void) int cCiTransportConnection::Poll(void)
{ {
if (state == stACTIVE) { if (state == stACTIVE) {
if (SendTPDU(T_DATA_LAST) == OK) { if (SendTPDU(T_DATA_LAST) == OK)
return RecvTPDU(); return RecvTPDU();
}
} }
return ERROR; return ERROR;
} }
@ -428,11 +436,12 @@ private:
int fd; int fd;
int numSlots; int numSlots;
cCiTransportConnection tc[MAX_CI_CONNECT]; cCiTransportConnection tc[MAX_CI_CONNECT];
bool ResetSlot(int Slot);
public: public:
cCiTransportLayer(int Fd, int NumSlots); cCiTransportLayer(int Fd, int NumSlots);
cCiTransportConnection *NewConnection(void); cCiTransportConnection *NewConnection(int Slot);
int Process(void); bool ResetSlot(int Slot);
bool ModuleReady(int Slot);
cCiTransportConnection *Process(int Slot);
}; };
cCiTransportLayer::cCiTransportLayer(int Fd, int NumSlots) cCiTransportLayer::cCiTransportLayer(int Fd, int NumSlots)
@ -441,46 +450,28 @@ cCiTransportLayer::cCiTransportLayer(int Fd, int NumSlots)
numSlots = NumSlots; numSlots = NumSlots;
for (int s = 0; s < numSlots; s++) for (int s = 0; s < numSlots; s++)
ResetSlot(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++) { for (int i = 0; i < MAX_CI_CONNECT; i++) {
if (tc[i].State() == stIDLE) { if (tc[i].State() == stIDLE) {
if (tc[i].CreateConnection() == OK) { dbgprotocol("Creating connection: slot %d, tcid %d\n", Slot, i + 1);
if (tc[i].RecvTPDU() == T_CTC_REPLY) tc[i].Init(fd, Slot, i + 1);
return &tc[i]; if (tc[i].CreateConnection() == OK)
} return &tc[i];
break; break;
} }
} }
return NULL; return NULL;
} }
#define CA_RESET_TIMEOUT 3 // seconds
bool cCiTransportLayer::ResetSlot(int Slot) bool cCiTransportLayer::ResetSlot(int Slot)
{ {
dbgprotocol("Resetting slot %d...", Slot); dbgprotocol("Resetting slot %d...", Slot);
ca_slot_info_t sinfo;
sinfo.num = Slot;
if (ioctl(fd, CA_RESET, 1 << Slot) != -1) { if (ioctl(fd, CA_RESET, 1 << Slot) != -1) {
time_t t0 = time(NULL); dbgprotocol("ok.\n");
do { return true;
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);
} }
else else
esyslog("ERROR: can't reset CAM slot %d: %m", Slot); esyslog("ERROR: can't reset CAM slot %d: %m", Slot);
@ -488,35 +479,55 @@ bool cCiTransportLayer::ResetSlot(int Slot)
return false; 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++) { for (int i = 0; i < MAX_CI_CONNECT; i++) {
cCiTransportConnection *Tc = &tc[i]; cCiTransportConnection *Tc = &tc[i];
if (Tc->State() == stACTIVE) { if (Tc->Slot() == Slot) {
if (!Tc->DataAvailable()) { switch (Tc->State()) {
if (Tc->Poll() != OK) case stCREATION:
;//XXX continue; case stACTIVE:
} if (!Tc->DataAvailable()) {
switch (Tc->LastResponse()) { if (Tc->Poll() != OK)
case T_REQUEST_TC: ;//XXX continue;
//XXX }
break; switch (Tc->LastResponse()) {
case T_DATA_MORE: case T_REQUEST_TC:
case T_DATA_LAST: //XXX
case T_CTC_REPLY: break;
case T_SB: case T_DATA_MORE:
if (Tc->DataAvailable()) case T_DATA_LAST:
Tc->RecvData(); case T_CTC_REPLY:
break; case T_SB:
case TIMEOUT: if (Tc->DataAvailable())
case ERROR: Tc->RecvData();
default: break;
//XXX Tc->state = stIDLE;//XXX Init()??? 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; break;
default: ;
} }
} }
} }
return OK; return NULL;
} }
// -- cCiSession ------------------------------------------------------------- // -- cCiSession -------------------------------------------------------------
@ -608,6 +619,7 @@ protected:
public: public:
cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc); cCiSession(int SessionId, int ResourceId, cCiTransportConnection *Tc);
virtual ~cCiSession(); virtual ~cCiSession();
const cCiTransportConnection *Tc(void) { return tc; }
int SessionId(void) { return sessionId; } int SessionId(void) { return sessionId; }
int ResourceId(void) { return resourceId; } int ResourceId(void) { return resourceId; }
virtual bool Process(int Length = 0, const uint8_t *Data = NULL); 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++) for (int i = 0; i < MAX_CI_SESSION; i++)
sessions[i] = NULL; sessions[i] = NULL;
tpl = new cCiTransportLayer(Fd, numSlots); tpl = new cCiTransportLayer(Fd, numSlots);
tc = tpl->NewConnection(); tc = NULL;
if (!tc)
isyslog("CAM: no CAM detected");
} }
cCiHandler::~cCiHandler() cCiHandler::~cCiHandler()
@ -1281,14 +1291,9 @@ cCiHandler *cCiHandler::CreateCiHandler(const char *FileName)
if (ioctl(fd_ca, CA_GET_CAP, &Caps) == 0) { if (ioctl(fd_ca, CA_GET_CAP, &Caps) == 0) {
int NumSlots = Caps.slot_num; int NumSlots = Caps.slot_num;
if (NumSlots > 0) { if (NumSlots > 0) {
dsyslog("CAM: found %d CAM slots", NumSlots); //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) { if (Caps.slot_type == CA_CI_LINK)
cCiHandler *CiHandler = new cCiHandler(fd_ca, NumSlots); return 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;
}
else else
esyslog("ERROR: CAM doesn't support link layer interface"); 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); *(short *)p = htons(SessionId);
p += 2; p += 2;
buffer[1] = p - buffer - 2; // length 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) cCiSession *cCiHandler::GetSessionBySessionId(int SessionId)
@ -1332,10 +1337,10 @@ cCiSession *cCiHandler::GetSessionBySessionId(int SessionId)
return NULL; return NULL;
} }
cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId) cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId, int Slot)
{ {
for (int i = 0; i < MAX_CI_SESSION; i++) { 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 sessions[i];
} }
return NULL; return NULL;
@ -1343,7 +1348,7 @@ cCiSession *cCiHandler::GetSessionByResourceId(int ResourceId)
cCiSession *cCiHandler::CreateSession(int ResourceId) cCiSession *cCiHandler::CreateSession(int ResourceId)
{ {
if (!GetSessionByResourceId(ResourceId)) { if (!GetSessionByResourceId(ResourceId, tc->Slot())) {
for (int i = 0; i < MAX_CI_SESSION; i++) { for (int i = 0; i < MAX_CI_SESSION; i++) {
if (!sessions[i]) { if (!sessions[i]) {
switch (ResourceId) { switch (ResourceId) {
@ -1403,81 +1408,107 @@ bool cCiHandler::CloseSession(int SessionId)
return false; return false;
} }
bool cCiHandler::Process(void) int cCiHandler::CloseAllSessions(int Slot)
{ {
if (tc) { int result = 0;
cMutexLock MutexLock(&mutex); for (int i = 0; i < MAX_CI_SESSION; i++) {
if (tpl->Process() == OK) { if (sessions[i] && sessions[i]->Tc()->Slot() == Slot) {
int Length; CloseSession(sessions[i]->SessionId());
const uint8_t *Data = tc->Data(Length); result++;
if (Data && Length > 1) { }
switch (*Data) { }
case ST_SESSION_NUMBER: if (Length > 4) { return result;
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;
} }
bool cCiHandler::EnterMenu(void) void cCiHandler::Process(void)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
//XXX slots??? for (int Slot = 0; Slot < numSlots; Slot++) {
cCiApplicationInformation *api = (cCiApplicationInformation *)GetSessionByResourceId(RI_APPLICATION_INFORMATION); 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; return api ? api->EnterMenu() : false;
} }
cCiMenu *cCiHandler::GetMenu(void) cCiMenu *cCiHandler::GetMenu(void)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
//XXX slots??? for (int Slot = 0; Slot < numSlots; Slot++) {
cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI); cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI, Slot);
return mmi ? mmi->Menu() : NULL; if (mmi)
return mmi->Menu();
}
return NULL;
} }
cCiEnquiry *cCiHandler::GetEnquiry(void) cCiEnquiry *cCiHandler::GetEnquiry(void)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
//XXX slots??? for (int Slot = 0; Slot < numSlots; Slot++) {
cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI); cCiMMI *mmi = (cCiMMI *)GetSessionByResourceId(RI_MMI, Slot);
return mmi ? mmi->Enquiry() : NULL; if (mmi)
return mmi->Enquiry();
}
return NULL;
} }
bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt) bool cCiHandler::SetCaPmt(cCiCaPmt &CaPmt)
{ {
cMutexLock MutexLock(&mutex); cMutexLock MutexLock(&mutex);
//XXX slots??? bool result = false;
cCiConditionalAccessSupport *cas = (cCiConditionalAccessSupport *)GetSessionByResourceId(RI_CONDITIONAL_ACCESS_SUPPORT); for (int Slot = 0; Slot < numSlots; Slot++) {
return cas ? cas->SendPMT(CaPmt) : false; 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); cMutexLock MutexLock(&mutex);
//XXX slots??? CloseAllSessions(Slot);
return false;//XXX not yet implemented return tpl->ResetSlot(Slot);
} }

11
ci.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __CI_H
@ -86,20 +86,21 @@ private:
int ResourceIdToInt(const uint8_t *Data); int ResourceIdToInt(const uint8_t *Data);
bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1); bool Send(uint8_t Tag, int SessionId, int ResourceId = 0, int Status = -1);
cCiSession *GetSessionBySessionId(int SessionId); cCiSession *GetSessionBySessionId(int SessionId);
cCiSession *GetSessionByResourceId(int ResourceId); cCiSession *GetSessionByResourceId(int ResourceId, int Slot);
cCiSession *CreateSession(int ResourceId); cCiSession *CreateSession(int ResourceId);
bool OpenSession(int Length, const uint8_t *Data); bool OpenSession(int Length, const uint8_t *Data);
bool CloseSession(int SessionId); bool CloseSession(int SessionId);
int CloseAllSessions(int Slot);
cCiHandler(int Fd, int NumSlots); cCiHandler(int Fd, int NumSlots);
public: public:
~cCiHandler(); ~cCiHandler();
static cCiHandler *CreateCiHandler(const char *FileName); static cCiHandler *CreateCiHandler(const char *FileName);
bool Process(void); void Process(void);
bool EnterMenu(void); bool EnterMenu(int Slot);
cCiMenu *GetMenu(void); cCiMenu *GetMenu(void);
cCiEnquiry *GetEnquiry(void); cCiEnquiry *GetEnquiry(void);
bool SetCaPmt(cCiCaPmt &CaPmt); bool SetCaPmt(cCiCaPmt &CaPmt);
bool Reset(void); bool Reset(int Slot);
}; };
#endif //__CI_H #endif //__CI_H

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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 #ifndef __CONFIG_H
@ -19,7 +19,7 @@
#include "device.h" #include "device.h"
#include "tools.h" #include "tools.h"
#define VDRVERSION "1.1.23" #define VDRVERSION "1.1.24"
#define MAXPRIORITY 99 #define MAXPRIORITY 99
#define MAXLIFETIME 99 #define MAXLIFETIME 99

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "dvbdevice.h"
@ -238,6 +238,7 @@ bool cDvbTuner::SetFrontend(void)
void cDvbTuner::Action(void) void cDvbTuner::Action(void)
{ {
time_t StartTime = time(NULL);
dsyslog("tuner thread started on device %d (pid=%d)", cardIndex + 1, getpid()); dsyslog("tuner thread started on device %d (pid=%d)", cardIndex + 1, getpid());
active = true; active = true;
while (active) { while (active) {
@ -258,24 +259,28 @@ void cDvbTuner::Action(void)
continue; continue;
} }
} }
if (ciHandler && !caSet) {//XXX TODO update in case the CA descriptors have changed if (ciHandler) {
uchar buffer[2048]; ciHandler->Process();
int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer); if (!caSet) {//XXX TODO update in case the CA descriptors have changed
if (length > 0) { uchar buffer[2048];
cCiCaPmt CaPmt(channel.Sid()); int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer);
CaPmt.AddCaDescriptor(length, buffer); if (length > 0) {
if (channel.Vpid()) cCiCaPmt CaPmt(channel.Sid());
CaPmt.AddPid(channel.Vpid()); CaPmt.AddCaDescriptor(length, buffer);
if (channel.Apid1()) if (channel.Vpid())
CaPmt.AddPid(channel.Apid1()); CaPmt.AddPid(channel.Vpid());
if (channel.Apid2()) if (channel.Apid1())
CaPmt.AddPid(channel.Apid2()); CaPmt.AddPid(channel.Apid1());
if (channel.Dpid1()) if (channel.Apid2())
CaPmt.AddPid(channel.Dpid1()); CaPmt.AddPid(channel.Apid2());
caSet = ciHandler->SetCaPmt(CaPmt); 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()); dsyslog("tuner thread ended on device %d (pid=%d)", cardIndex + 1, getpid());
} }

22
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * 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" #include "menu.h"
@ -1537,6 +1537,7 @@ cMenuCam::cMenuCam(cCiMenu *CiMenu)
Add(new cOsdItem(ciMenu->SubTitleText())); Add(new cOsdItem(ciMenu->SubTitleText()));
Add(new cOsdItem(ciMenu->BottomText())); Add(new cOsdItem(ciMenu->BottomText()));
Display(); Display();
dsyslog("CAM: Menu - %s", ciMenu->TitleText());
} }
cMenuCam::~cMenuCam() cMenuCam::~cMenuCam()
@ -1622,7 +1623,6 @@ cOsdObject *CamControl(void)
if (Device) { if (Device) {
cCiHandler *CiHandler = Device->CiHandler(); cCiHandler *CiHandler = Device->CiHandler();
if (CiHandler) { if (CiHandler) {
CiHandler->Process();
cCiMenu *CiMenu = CiHandler->GetMenu(); cCiMenu *CiMenu = CiHandler->GetMenu();
if (CiMenu) if (CiMenu)
return new cMenuCam(CiMenu); return new cMenuCam(CiMenu);
@ -2069,7 +2069,7 @@ class cMenuSetupCICAM : public cMenuSetupBase {
private: private:
int helpKeys; int helpKeys;
void SetHelpKeys(void); void SetHelpKeys(void);
cCiHandler *GetCurrentCiHandler(void); cCiHandler *GetCurrentCiHandler(int *Slot = NULL);
eOSState Menu(void); eOSState Menu(void);
eOSState Reset(void); eOSState Reset(void);
public: public:
@ -2091,9 +2091,11 @@ cMenuSetupCICAM::cMenuSetupCICAM(void)
SetHelpKeys(); SetHelpKeys();
} }
cCiHandler *cMenuSetupCICAM::GetCurrentCiHandler(void) cCiHandler *cMenuSetupCICAM::GetCurrentCiHandler(int *Slot)
{ {
cDevice *Device = cDevice::GetDevice(Current() / 2); cDevice *Device = cDevice::GetDevice(Current() / 2);
if (Slot)
*Slot = Current() % 2;
return Device ? Device->CiHandler() : NULL; return Device ? Device->CiHandler() : NULL;
} }
@ -2112,8 +2114,9 @@ void cMenuSetupCICAM::SetHelpKeys(void)
eOSState cMenuSetupCICAM::Menu(void) eOSState cMenuSetupCICAM::Menu(void)
{ {
cCiHandler *CiHandler = GetCurrentCiHandler(); int Slot = 0;
if (CiHandler && CiHandler->EnterMenu()) cCiHandler *CiHandler = GetCurrentCiHandler(&Slot);
if (CiHandler && CiHandler->EnterMenu(Slot))
return osEnd; // the CAM menu will be executed explicitly from the main loop return osEnd; // the CAM menu will be executed explicitly from the main loop
else else
Interface->Error(tr("Can't open CAM menu!")); Interface->Error(tr("Can't open CAM menu!"));
@ -2122,9 +2125,12 @@ eOSState cMenuSetupCICAM::Menu(void)
eOSState cMenuSetupCICAM::Reset(void) eOSState cMenuSetupCICAM::Reset(void)
{ {
cCiHandler *CiHandler = GetCurrentCiHandler(); int Slot = 0;
if (CiHandler && CiHandler->Reset()) cCiHandler *CiHandler = GetCurrentCiHandler(&Slot);
if (CiHandler && CiHandler->Reset(Slot)) {
Interface->Info(tr("CAM has been reset")); Interface->Info(tr("CAM has been reset"));
return osEnd;
}
else else
Interface->Error(tr("Can't reset CAM!")); Interface->Error(tr("Can't reset CAM!"));
return osContinue; return osContinue;

4
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * 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 <getopt.h> #include <getopt.h>
@ -469,7 +469,7 @@ int main(int argc, char *argv[])
} }
} }
// CAM control: // CAM control:
if (!Menu) if (!Interface->IsOpen())
Menu = CamControl(); Menu = CamControl();
// User Input: // User Input:
cOsdObject *Interact = Menu ? Menu : cControl::Control(); cOsdObject *Interact = Menu ? Menu : cControl::Control();