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:
parent
b7777e230c
commit
777f330c77
@ -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
|
||||||
|
6
HISTORY
6
HISTORY
@ -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
311
ci.c
@ -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
11
ci.h
@ -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
|
||||||
|
4
config.h
4
config.h
@ -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
|
||||||
|
39
dvbdevice.c
39
dvbdevice.c
@ -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
22
menu.c
@ -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
4
vdr.c
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user