mirror of
				https://github.com/vdr-projects/vdr.git
				synced 2025-03-01 10:50:46 +00:00 
			
		
		
		
	Improved CAM support
This commit is contained in:
		| @@ -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. | ||||||
|   | |||||||
							
								
								
									
										221
									
								
								ci.c
									
									
									
									
									
								
							
							
						
						
									
										221
									
								
								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; | ||||||
|  |         if (RecvTPDU() == T_CTC_REPLY) | ||||||
|            return OK; |            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,10 +421,9 @@ 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,58 +450,54 @@ 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); | ||||||
|  |          if (tc[i].CreateConnection() == OK) | ||||||
|             return &tc[i]; |             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); |  | ||||||
|      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"); |      dbgprotocol("ok.\n"); | ||||||
|      return true; |      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); | ||||||
|   dbgprotocol("failed!\n"); |   dbgprotocol("failed!\n"); | ||||||
|   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) { | ||||||
|  |          switch (Tc->State()) { | ||||||
|  |            case stCREATION: | ||||||
|  |            case stACTIVE: | ||||||
|                 if (!Tc->DataAvailable()) { |                 if (!Tc->DataAvailable()) { | ||||||
|                    if (Tc->Poll() != OK) |                    if (Tc->Poll() != OK) | ||||||
|                       ;//XXX continue; |                       ;//XXX continue; | ||||||
| @@ -512,11 +517,17 @@ int cCiTransportLayer::Process(void) | |||||||
|                   case ERROR: |                   case ERROR: | ||||||
|                   default: |                   default: | ||||||
|                        //XXX Tc->state = stIDLE;//XXX Init()??? |                        //XXX Tc->state = stIDLE;//XXX Init()??? | ||||||
|  |                        return NULL; | ||||||
|                        break; |                        break; | ||||||
|                   } |                   } | ||||||
|  |                 //XXX this will only work with _one_ transport connection per slot! | ||||||
|  |                 return Tc; | ||||||
|  |                 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,11 +1408,24 @@ bool cCiHandler::CloseSession(int SessionId) | |||||||
|   return false; |   return false; | ||||||
| } | } | ||||||
|  |  | ||||||
| bool cCiHandler::Process(void) | int cCiHandler::CloseAllSessions(int Slot) | ||||||
|  | { | ||||||
|  |   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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void cCiHandler::Process(void) | ||||||
| { | { | ||||||
|   if (tc) { |  | ||||||
|   cMutexLock MutexLock(&mutex); |   cMutexLock MutexLock(&mutex); | ||||||
|      if (tpl->Process() == OK) { |   for (int Slot = 0; Slot < numSlots; Slot++) { | ||||||
|  |       tc = tpl->Process(Slot); | ||||||
|  |       if (tc) { | ||||||
|          int Length; |          int Length; | ||||||
|          const uint8_t *Data = tc->Data(Length); |          const uint8_t *Data = tc->Data(Length); | ||||||
|          if (Data && Length > 1) { |          if (Data && Length > 1) { | ||||||
| @@ -1416,68 +1434,81 @@ bool cCiHandler::Process(void) | |||||||
|                                                   int SessionId = ntohs(*(short *)&Data[2]); |                                                   int SessionId = ntohs(*(short *)&Data[2]); | ||||||
|                                                   cCiSession *Session = GetSessionBySessionId(SessionId); |                                                   cCiSession *Session = GetSessionBySessionId(SessionId); | ||||||
|                                                   if (Session) |                                                   if (Session) | ||||||
|                                                     return Session->Process(Length - 4, Data + 4); |                                                      Session->Process(Length - 4, Data + 4); | ||||||
|                                                  else { |                                                   else | ||||||
|                                                      esyslog("ERROR: unknown session id: %d", SessionId); |                                                      esyslog("ERROR: unknown session id: %d", SessionId); | ||||||
|                                                     return false; |  | ||||||
|                                                     } |  | ||||||
|                                                   } |                                                   } | ||||||
|                                                break; |                                                break; | ||||||
|              case ST_OPEN_SESSION_REQUEST:    return OpenSession(Length, Data); |               case ST_OPEN_SESSION_REQUEST:    OpenSession(Length, Data); | ||||||
|  |                                                break; | ||||||
|               case ST_CLOSE_SESSION_REQUEST:   if (Length == 4) |               case ST_CLOSE_SESSION_REQUEST:   if (Length == 4) | ||||||
|                                                  return CloseSession(ntohs(*(short *)&Data[2])); |                                                   CloseSession(ntohs(*(short *)&Data[2])); | ||||||
|                                                break; |                                                break; | ||||||
|               case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default |               case ST_CREATE_SESSION_RESPONSE: //XXX fall through to default | ||||||
|               case ST_CLOSE_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); |               default: esyslog("ERROR: unknown session tag: %02X", *Data); | ||||||
|                       return false; |  | ||||||
|               } |               } | ||||||
|            return true; |             } | ||||||
|  |          } | ||||||
|  |       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++) { |   for (int i = 0; i < MAX_CI_SESSION; i++) { | ||||||
|       if (sessions[i]) |       if (sessions[i]) | ||||||
|                sessions[i]->Process();//XXX retval??? |          sessions[i]->Process(); | ||||||
|       } |       } | ||||||
| } | } | ||||||
|      } |  | ||||||
|   return false; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool cCiHandler::EnterMenu(void) | bool cCiHandler::EnterMenu(int Slot) | ||||||
| { | { | ||||||
|   cMutexLock MutexLock(&mutex); |   cMutexLock MutexLock(&mutex); | ||||||
|   //XXX slots??? |   cCiApplicationInformation *api = (cCiApplicationInformation *)GetSessionByResourceId(RI_APPLICATION_INFORMATION, Slot); | ||||||
|   cCiApplicationInformation *api = (cCiApplicationInformation *)GetSessionByResourceId(RI_APPLICATION_INFORMATION); |  | ||||||
|   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 | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								dvbdevice.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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,7 +259,9 @@ void cDvbTuner::Action(void) | |||||||
|               continue; |               continue; | ||||||
|               } |               } | ||||||
|            } |            } | ||||||
|         if (ciHandler && !caSet) {//XXX TODO update in case the CA descriptors have changed |         if (ciHandler) { | ||||||
|  |            ciHandler->Process(); | ||||||
|  |            if (!caSet) {//XXX TODO update in case the CA descriptors have changed | ||||||
|               uchar buffer[2048]; |               uchar buffer[2048]; | ||||||
|               int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer); |               int length = cSIProcessor::GetCaDescriptors(channel.Source(), channel.Frequency(), channel.Sid(), sizeof(buffer), buffer); | ||||||
|               if (length > 0) { |               if (length > 0) { | ||||||
| @@ -275,7 +278,9 @@ void cDvbTuner::Action(void) | |||||||
|                  caSet = ciHandler->SetCaPmt(CaPmt); |                  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(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user