DVBCore  20.3.0
DVBCore Documentation
stbcicc.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2016 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  *
4  * This file is part of a DTVKit Software Component
5  * You are permitted to copy, modify or distribute this file subject to the terms
6  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
7  *
8  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
9  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
10  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * If you or your organisation is not a member of DTVKit then you have access
13  * to this source code outside of the terms of the licence agreement
14  * and you are expected to delete this and any associated files immediately.
15  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
16  *******************************************************************************/
23 //#define DEBUG_PRINTING_ENABLED
24 
25 /*---includes for this file--------------------------------------------------*/
26 
27 /* compiler library header files */
28 
29 /* third party header files */
30 #include <string.h>
31 
32 /* DVBCore header files */
33 #include "techtype.h"
34 #include "dbgfuncs.h"
35 #include "stbhwos.h"
36 #include "stbhwci.h"
37 #include "stbci.h"
38 #include "stberc.h"
39 #include "stbhwav.h"
40 #include "stbheap.h"
41 #include "stbdpc.h"
42 
43 #include "stbcicc.h"
44 #include "stbci_int.h"
45 
46 /*---constant definitions for this file--------------------------------------*/
47 
48 #define MAX_CICAM_BRANDS 126
49 
50 //#define DEBUG_CC
51 #ifdef DEBUG_CC
52  #define DBG_CC(x, ...) STB_SPDebugWrite( "%s:%d " x, __FUNCTION__, __LINE__, ##__VA_ARGS__);
53 #else
54  #define DBG_CC(x, ...)
55 #endif
56 
57 //#define DEBUG_REC
58 #ifdef DEBUG_REC
59  #define DBG_REC(x, ...) STB_SPDebugWrite( x, ##__VA_ARGS__ );
60 #else
61  #define DBG_REC(x, ...)
62 #endif
63 
64 /*---local typedef enums for this file-------------------------------------*/
65 
66 typedef enum
67 {
68  CI_AUTH_NONE = 0,
69  CI_AUTH_IN_PROGRESS,
70  CI_AUTH_SUCCESS,
71  CI_AUTH_FAIL
72 } E_CI_AUTH_STATUS;
73 
74 /*---local typedef structs for this file-------------------------------------*/
75 
76 typedef struct ci_protection
77 {
78  BOOLEAN sdt_acquisition_complete;
79  BOOLEAN free_ci_mode_flag;
80  BOOLEAN match_brand_flag;
81  U8BIT number_of_entries;
82  U16BIT entries[MAX_CICAM_BRANDS];
84 
85 typedef struct s_slot_state
86 {
87  struct s_slot_state *next;
88 
89  /* Authenticated CI+ module */
90  E_CI_AUTH_STATUS auth_status;
91 
92  U16BIT program_number;
93 
94  /* CI+ CAM brand ID */
95  U16BIT cicam_brand_id;
96 
97  /* Slot_id (0, 1, 2, ...) */
98  U8BIT slot_id;
99 
100  /* URI information */
101  S_STB_CI_URI uri;
102 
103  BOOLEAN ready;
104  BOOLEAN disabled;
105 
106  /* Recording */
107  BOOLEAN recording;
108  U16BIT record_service_id;
109  BOOLEAN op_mode_set;
110  E_STB_CI_OPERATING_MODE operating_mode;
111  S_STB_CI_URI recording_uri;
112  U8BIT recording_licence_status;
113  U8BIT *recording_licence;
114  U16BIT recording_licence_len;
115  U8BIT record_age_rating;
116  U8BIT record_private_data[CIP_PIN_PRIVATE_DATA_SIZE];
117  S_STB_CI_DATE pin_event_date;
118  S_STB_CI_TIME pin_event_time;
119  U8BIT record_pin_status;
120 
121  BOOLEAN pin_caps_requested;
122  BOOLEAN pin_caps_received;
123  E_STB_CI_PIN_CAPS pin_caps;
124  S_STB_CI_DATE pin_date;
125  S_STB_CI_TIME pin_time;
126  U8BIT age_rating;
127 
128  /* Playback */
129  BOOLEAN play_pin_sent;
130  U16BIT play_service_id;
131  S_STB_CI_URI playback_uri;
132  U8BIT playback_licence_status;
133  U8BIT *playback_licence;
134  U16BIT playback_licence_len;
135 } S_SLOT_STATE;
136 
137 /*---local (static) variable declarations for this file----------------------*/
138 /* (internal variables declared static to make them local) */
139 
140 static S_CI_PROTECTION ci_protection_info = {FALSE, FALSE, FALSE, 0, {0}};
141 static S_SLOT_STATE *cicc_slots = NULL;
142 static void *cicc_mutex;
143 
144 static S_SLOT_STATE *FindSlot(U8BIT slot_id);
145 static BOOLEAN IsServiceAllowed(S_SLOT_STATE *slot_state,
146  U8BIT *ci_protection_descriptor);
147 static void ParseCiProtectionDescriptor(U8BIT *ci_protection_descriptor);
148 static void ApplyURIv1(S_STB_CI_URI *uri, BOOLEAN playback);
149 static void ApplyURIv2(S_STB_CI_URI *uri, BOOLEAN playback);
150 static void ApplyInvalidURI(void);
151 static void PackUri(S_STB_CI_URI *uri, U8BIT buffer[CIP_URI_LEN]);
152 static void UnpackUri(U8BIT buffer[CIP_URI_LEN], S_STB_CI_URI *uri);
153 
154 /*---global function definitions---------------------------------------------*/
155 
160 {
161  cicc_mutex = STB_OSCreateMutex();
164 }
165 
170 void STB_CiCcNotifyModuleInsert(U8BIT slot_id)
171 {
172  S_SLOT_STATE *slot_info;
173 
174  FUNCTION_START(STB_CiCcNotifyModuleInsert);
175 
176  DBGPRINT("slot_id=%d", slot_id)
177 
178  slot_info = FindSlot(slot_id);
179  if (slot_info != NULL)
180  {
181  DBGPRINT("CAM already inserted to slot %d! Inconsistent state!", slot_id);
182  }
183  else
184  {
185  slot_info = STB_GetMemory(sizeof(S_SLOT_STATE));
186  if (slot_info != NULL)
187  {
188  slot_info->ready = FALSE;
189  slot_info->disabled = FALSE;
190  slot_info->slot_id = slot_id;
191  slot_info->auth_status = CI_AUTH_NONE;
192  slot_info->cicam_brand_id = 0x0000;
193  slot_info->program_number = 0xFFFF;
194  slot_info->play_service_id = 0xFFFF;
195  slot_info->record_service_id = 0xFFFF;
196 
197  slot_info->recording = FALSE;
198  slot_info->op_mode_set = FALSE;
199  slot_info->operating_mode = STB_CI_MODE_UNATTENDED_RECORDING;
200  slot_info->recording_licence = NULL;
201  slot_info->recording_licence_len = 0;
202  slot_info->pin_caps_requested = FALSE;
203  slot_info->pin_caps_received = FALSE;
204  slot_info->pin_caps = STB_CI_PIN_CAPS_NONE;
205  slot_info->play_pin_sent = FALSE;
206  slot_info->playback_licence = NULL;
207  slot_info->playback_licence_len = 0;
208 
209  STB_OSMutexLock(cicc_mutex);
210  slot_info->next = cicc_slots;
211  cicc_slots = slot_info;
212  STB_OSMutexUnlock(cicc_mutex);
213 
214  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_INSERT, &slot_id, sizeof(slot_id));
215  }
216  }
217 
218  FUNCTION_FINISH(STB_CiCcNotifyModuleInsert);
219 }
220 
227 void STB_CINotifyModuleReady(U8BIT slot_id, BOOLEAN ci_plus, U32BIT mask)
228 {
229  S_SLOT_STATE *slot;
230 
231  FUNCTION_START(STB_CINotifyModuleReady);
232 
233  DBGPRINT("slot_id=%d", slot_id)
234 
235  slot = FindSlot(slot_id);
236  if (slot != NULL)
237  {
238  slot->ready = TRUE;
239  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_SLOT_STATUS_UPDATED, &slot_id, sizeof slot_id);
240  }
241 
242  FUNCTION_FINISH(STB_CINotifyModuleReady);
243 }
244 
249 void STB_CiCcNotifyModuleRemove(U8BIT slot_id)
250 {
251  S_SLOT_STATE *slot;
252 
253  FUNCTION_START(STB_CiCcNotifyModuleRemove);
254 
255  DBGPRINT("slot_id=%d", slot_id)
256 
257  STB_CiCaDisable(slot_id);
258  STB_CiKeysDisable(slot_id);
259 
260  slot = FindSlot(slot_id);
261  if (slot != NULL)
262  {
263  slot->disabled = TRUE;
264  }
265 
266  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_REMOVE, &slot_id, sizeof(slot_id));
267 
268  FUNCTION_FINISH(STB_CiCcNotifyModuleRemove);
269 }
270 
275 void STB_CiCcRemove(U8BIT slot_id)
276 {
277  S_SLOT_STATE *slot;
278  S_SLOT_STATE **pslot;
279 
280  FUNCTION_START(STB_CiCcRemove);
281 
282  pslot = &cicc_slots;
283  STB_OSMutexLock(cicc_mutex);
284  slot = cicc_slots;
285  while (slot != NULL)
286  {
287  if (slot->slot_id == slot_id)
288  {
289  *pslot = slot->next;
290  if (slot->recording_licence != NULL)
291  {
292  STB_FreeMemory(slot->recording_licence);
293  slot->recording_licence = NULL;
294  }
295  if (slot->playback_licence != NULL)
296  {
297  STB_FreeMemory(slot->playback_licence);
298  slot->playback_licence = NULL;
299  }
300  STB_FreeMemory(slot);
301  break;
302  }
303  pslot = &(slot->next);
304  slot = slot->next;
305  }
306  STB_OSMutexUnlock(cicc_mutex);
307 
308  STB_CiKeysRemove(slot_id);
309  STB_CiCaRemove(slot_id);
310 
311  FUNCTION_FINISH(STB_CiCcRemove);
312 }
313 
319 BOOLEAN STB_CiCcIsSlotReady(U8BIT slot_id)
320 {
321  S_SLOT_STATE *slot;
322  BOOLEAN ready;
323 
324  FUNCTION_START(STB_CiCcIsSlotReady);
325 
326  slot = FindSlot(slot_id);
327  if (slot != NULL)
328  {
329  ready = slot->ready;
330  }
331  else
332  {
333  ready = FALSE;
334  }
335 
336  FUNCTION_FINISH(STB_CiCcIsSlotReady);
337 
338  return ready;
339 }
340 
349 BOOLEAN STB_CiCcIsServiceAllowed(U8BIT slot_id, U8BIT *ci_prot_desc)
350 {
351  S_SLOT_STATE *slot;
352  BOOLEAN allowed;
353 
354  FUNCTION_START(STB_CiCcIsServiceAllowed);
355 
356  allowed = FALSE;
357 
358  slot = FindSlot(slot_id);
359  if (slot != NULL && slot->ready)
360  {
361  allowed = IsServiceAllowed(slot, ci_prot_desc);
362  }
363 
364  FUNCTION_FINISH(STB_CiCcIsServiceAllowed);
365 
366  return allowed;
367 }
368 
374 BOOLEAN STB_CiCcAuthenticated(U8BIT slot_id)
375 {
376  S_SLOT_STATE *slot;
377  BOOLEAN auth;
378 
379  FUNCTION_START(STB_CiCcAuthenticated);
380 
381  auth = FALSE;
382 
383  slot = FindSlot(slot_id);
384  if (slot != NULL && slot->ready)
385  {
386  auth = (slot->auth_status == CI_AUTH_SUCCESS)? TRUE : FALSE;
387  }
388 
389  FUNCTION_FINISH(STB_CiCcAuthenticated);
390 
391  return auth;
392 }
393 
399 U8BIT STB_CiCcFindSlotForCicamId(U8BIT cicam_id[CIP_CICAM_ID_LEN])
400 {
401  U8BIT slot_id, num_slots;
402  U8BIT id[CIP_CICAM_ID_LEN];
403 
404  FUNCTION_START(FindSlotForCicamId);
405  num_slots = STB_CIGetSlotCount();
406  for (slot_id = 0; slot_id != num_slots; slot_id++)
407  {
408  if (STB_CIGetCicamId(slot_id, id))
409  {
410  if (memcmp(id, cicam_id, CIP_CICAM_ID_LEN) == 0)
411  {
412  /* Slot with same CAM id found */
413  break;
414  }
415  }
416  }
417  if (slot_id == num_slots)
418  {
419  slot_id = INVALID_RES_ID;
420  }
421  FUNCTION_FINISH(FindSlotForCicamId);
422 
423  return(slot_id);
424 }
425 
434 void STB_CiCcSetSDTAcquisitionStatus(BOOLEAN complete)
435 {
436  FUNCTION_START(STB_CiCcSetSDTAcquisitionStatus);
437  DBGPRINT("%s", complete ? "TRUE" : "FALSE")
438  ci_protection_info.sdt_acquisition_complete = complete;
439  FUNCTION_FINISH(STB_CiCcSetSDTAcquisitionStatus);
440 }
441 
449 void STB_CiCcGetUsageRulesInfo(U8BIT slot_id, U16BIT service_id,
450  U8BIT raw_uri[CIP_URI_LEN])
451 {
452  S_SLOT_STATE *slot_state;
453 
454  FUNCTION_START(STB_CiCcGetUsageRulesInfo);
455 
456  memset(raw_uri, 0, CIP_URI_LEN);
457 
458  slot_state = FindSlot(slot_id);
459  if ((slot_state != NULL) && (slot_state->program_number == service_id))
460  {
461  DBGPRINT("Found URI for service_id = %d", service_id)
462  PackUri(&slot_state->uri, raw_uri);
463  }
464  else
465  {
466  DBGPRINT("cannot find URI")
468  }
469 
470  FUNCTION_FINISH(STB_CiCcGetUsageRulesInfo);
471 }
472 
477 void STB_CiCcGetDefaultUsageRulesInfo(U8BIT raw_uri[CIP_URI_LEN])
478 {
479  FUNCTION_START(STB_CiCcGetDefaultUsageRulesInfo);
480 
481  memset(raw_uri, 0x00, CIP_URI_LEN);
482 
483  /* Set default URI with emi bits set so that HDCP is required */
484  raw_uri[0] = 0x01;
485  raw_uri[1] = 0x30;
486 
487  FUNCTION_FINISH(STB_CiCcGetDefaultUsageRulesInfo);
488 }
489 
495 U32BIT STB_CiCcGetRetentionLimit(U8BIT raw_uri[CIP_URI_LEN])
496 {
497  S_STB_CI_URI uri;
498  U32BIT retention_limit;
499 
500  FUNCTION_START(STB_CiCcGetRetentionLimit);
501 
502  /* No limit unless explicitly limited */
503  retention_limit = 0;
504 
505  UnpackUri(raw_uri, &uri);
506  if ((uri.protocol_version == 0x01) || (uri.protocol_version == 0x02))
507  {
508  if (uri.rl_copy_control_info == 0x0)
509  {
510  /* 90 minutes */
511  retention_limit = 90;
512  }
513  else if (uri.rl_copy_control_info == 0x1)
514  {
515  /* 6 hours */
516  retention_limit = 6 * 60;
517  }
518  else if (uri.rl_copy_control_info == 0x2)
519  {
520  /* 12 hours */
521  retention_limit = 12 * 60;
522  }
523  else
524  {
525  if (uri.protocol_version == 0x01)
526  {
527  /* 1-61 multiples of 24 hours */
528  retention_limit = (uri.rl_copy_control_info - 2) * 24 * 60;
529  }
530  else if (uri.rl_copy_control_info != 0xff)
531  {
532  /* 1-252 multiples of 24 hours */
533  retention_limit = (uri.rl_copy_control_info - 2) * 24 * 60;
534  }
535  }
536  }
537 
538  FUNCTION_FINISH(STB_CiCcGetRetentionLimit);
539 
540  return retention_limit;
541 }
542 
547 void STB_CiCcApplyUsageRulesInfo(U8BIT raw_uri[CIP_URI_LEN])
548 {
549  S_STB_CI_URI uri;
550 
551  FUNCTION_START(STB_CiCcApplyUsageRulesInfo);
552 
553  UnpackUri(raw_uri, &uri);
554 
555  switch (uri.protocol_version)
556  {
557  case 0x1:
558  ApplyURIv1(&uri, FALSE);
559  break;
560 
561  case 0x02:
562  ApplyURIv2(&uri, FALSE);
563  break;
564 
565  default:
566  DBGPRINT("Invalid URI version")
567  ApplyInvalidURI();
568  break;
569  }
570 
571  FUNCTION_FINISH(STB_CiCcApplyUsageRulesInfo);
572 }
573 
579 {
580  S_STB_CI_URI uri;
581 
583 
584  UnpackUri(raw_uri, &uri);
585 
586  switch (uri.protocol_version)
587  {
588  case 0x1:
589  ApplyURIv1(&uri, TRUE);
590  break;
591 
592  case 0x02:
593  ApplyURIv2(&uri, TRUE);
594  break;
595 
596  default:
597  DBGPRINT("Invalid URI version")
598  ApplyInvalidURI();
599  break;
600  }
601 
603 }
604 
609 BOOLEAN STB_CiCcIsHDCPRequired(U16BIT service_id)
610 {
611  S_SLOT_STATE *slot_info;
612  BOOLEAN required;
613 
614  FUNCTION_START(STB_CiCcIsHDCPRequired);
615 
616  required = FALSE;
617 
618  slot_info = cicc_slots;
619  while (slot_info != NULL)
620  {
621  if (slot_info->program_number == service_id)
622  {
623  /* If program_number is set, the URI has been notified.
624  * Any valid URI requires HDCP, so the answer is TRUE.
625  */
626  required = TRUE;
627  break;
628  }
629  slot_info = slot_info->next;
630  }
631 
632  FUNCTION_FINISH(STB_CiCcIsHDCPRequired);
633 
634  return required;
635 }
636 
637 /*****************************************************************************
638  *
639  * CONTENT CONTROL FUNCTIONS
640  *
641  ****************************************************************************/
642 
649 void STB_CINotifyProgress(U8BIT slot_id, E_STB_CI_CC_STATE state, U16BIT cicam_brand_id)
650 {
651  S_SLOT_STATE *slot_state;
652  U8BIT path, tuner_path;
653 
654  FUNCTION_START(STB_CINotifyProgress);
655 
656  DBG_CC("State: %s, CICAM brand ID: %04x",
657  state == STB_CI_CC_START ? "STB_CI_CC_START" :
658  state == STB_CI_CC_VERIFIED ? "STB_CI_CC_VERIFIED" :
659  state == STB_CI_CC_CERT_EXPIRED ? "STB_CI_CC_CERT_EXPIRED" :
660  state == STB_CI_CC_PROTOCOL_ERROR ? "STB_CI_CC_PROTOCOL_ERROR" :
661  state == STB_CI_CC_AUTH_ERROR ? "STB_CI_CC_AUTH_ERROR" :
662  "UNKNOWN", cicam_brand_id)
663 
664  slot_state = FindSlot(slot_id);
665  if (slot_state != NULL)
666  {
667  if (STB_CIGetContentControlVersion(slot_id) >= 2)
668  {
669  if (!slot_state->pin_caps_requested)
670  {
671  DBG_CC("%s(%u): Requesting PIN capabilities", __FUNCTION__, slot_id)
672 
673  slot_state->pin_caps_received = FALSE;
674 
675  if (STB_CIRequestPinCaps(slot_id))
676  {
677  slot_state->pin_caps_requested = TRUE;
678  }
679 #ifdef DEBUG_CC
680  else
681  {
682  DBG_CC("%s(%u): Failed to request PIN capabilities", __FUNCTION__, slot_id)
683  }
684 #endif
685  }
686  }
687 
688  switch (state)
689  {
690  case STB_CI_CC_START:
691  {
692  slot_state->auth_status = CI_AUTH_IN_PROGRESS;
693 
694  /* The CICAM needs the TS to have the correct time to evaluate the certificates. At the
695  end of the certification the DVB stack will re-evaluate the necessity to have the TS
696  routed through the CICAM */
697  if ((path = STB_DPGetLivePath()) != INVALID_RES_ID)
698  {
699  if ((tuner_path = STB_DPGetPathTuner(path)) != INVALID_RES_ID)
700  {
701  STB_CIRouteTS(tuner_path, slot_state->slot_id, TRUE);
702  }
703  }
704  break;
705  }
706  case STB_CI_CC_AUTH_ERROR:
707  case STB_CI_CC_STATUS_AUTHENTICATION_FAILED:
708  case STB_CI_CC_PROTOCOL_ERROR:
709  {
710  slot_state->auth_status = CI_AUTH_FAIL;
711  break;
712  }
713  case STB_CI_CC_VERIFIED:
714  {
715  slot_state->auth_status = CI_AUTH_SUCCESS;
716  slot_state->cicam_brand_id = cicam_brand_id;
717  break;
718  }
719  default:
720  {
721  break;
722  }
723  }
724  }
725 
726  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_SLOT_STATUS_UPDATED, &slot_id, sizeof slot_id);
727 
728  FUNCTION_FINISH(STB_CINotifyProgress);
729 }
730 
731 
738 void STB_CINotifyURI(U8BIT slot_id, U16BIT program_number, S_STB_CI_URI *uri)
739 {
740  S_SLOT_STATE *slot_state;
741 
742  FUNCTION_START(STB_CINotifyURI);
743 
744  slot_state = FindSlot(slot_id);
745  if (slot_state != NULL)
746  {
747  DBGPRINT("Storing URI for program_number = %d", program_number)
748  DBGPRINT("URI = {pv=%d, aps=%d, emi=%d, ict=%d, rct=%d, dot=%d, rl=%d",
749  uri->protocol_version,
750  uri->aps_copy_control_info,
751  uri->emi_copy_control_info,
752  uri->ict_copy_control_info,
753  uri->rct_copy_control_info,
754  uri->dot_copy_control_info,
755  uri->rl_copy_control_info)
756  slot_state->program_number = program_number;
757  slot_state->uri = *uri;
758 
759  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_URI_UPDATED, &slot_id, sizeof(slot_id));
760  }
761 
762  FUNCTION_FINISH(STB_CINotifyURI);
763 }
764 
779 U8BIT STB_CINotifySRM(U8BIT slot_id, E_STB_SRM_DATA_TYPE srm_type, U8BIT *data, U16BIT len)
780 {
781  U8BIT rc;
782  E_STB_AV_SRM_REPLY srm_reply;
783 
784  FUNCTION_START(STB_CINotifySRM);
785  USE_UNWANTED_PARAM(slot_id);
786 
787  if (srm_type == STB_CI_SRM_HDCP)
788  {
789  srm_reply = STB_AVApplySRM(0, data, len);
790  switch (srm_reply)
791  {
792  case SRM_OK:
793  rc = STB_CI_SRM_OK;
794  break;
795  case SRM_BUSY:
796  rc = STB_CI_SRM_HOST_BUSY;
797  break;
798  case SRM_NOT_REQUIRED:
799  rc = STB_CI_SRM_NOT_REQUIRED;
800  break;
801  default:
802  /* Unknown response, use another */
803  DBGPRINT("Unexpected reply 0x%x", srm_reply)
804  rc = STB_CI_SRM_HOST_BUSY;
805  }
806  }
807  else /*srm_type == STB_CI_SRM_DTCP*/
808  {
809  DBGPRINT("DTCP not supported")
810  rc = STB_CI_SRM_NO_CC_SUPPORT;
811  }
812 
813  FUNCTION_FINISH(STB_CINotifySRM);
814 
815  return rc;
816 }
817 
818 /*****************************************************************************
819  *
820  * Function Name: STB_CINotifyPinCaps
821  *
822  * Description: This function is called by the CI+ stack to send information
823  * about PIN code capabilities.
824  *
825  * Parameters: slot_id - zero-based CI slot identifier (0, 1, ...)
826  * capability - PIN code capability
827  * pin_date - date of last PIN update
828  * pin_time - time of last PIN update
829  * rating - current rating for CICAM to request PIN
830  *
831  * Returns: Nothing
832  *
833  ****************************************************************************/
834 void STB_CINotifyPinCaps(U8BIT slot_id, E_STB_CI_PIN_CAPS capability,
835  S_STB_CI_DATE *pin_date, S_STB_CI_TIME *pin_time,
836  U8BIT rating)
837 {
838  S_SLOT_STATE *slot_state;
839 
840  FUNCTION_START(STB_CINotifyPinCaps);
841 
842  DBG_CC("(slot=%u, caps=%u, rating=%u)", slot_id, capability, rating)
843 
844  if ((slot_state = FindSlot(slot_id)) != NULL)
845  {
846  if (slot_state->pin_caps_requested)
847  {
848  slot_state->age_rating = rating;
849  slot_state->pin_caps = capability;
850  slot_state->pin_caps_received = TRUE;
851  slot_state->pin_date = *pin_date;
852  slot_state->pin_time = *pin_time;
853  }
854 #ifdef DEBUG_CC
855  else
856  {
857  DBG_CC("%s(%u): PIN capabilities weren't requested!", __FUNCTION__, slot_id)
858  }
859 #endif
860  }
861 
862  FUNCTION_FINISH(STB_CINotifyPinCaps);
863 }
864 
873 BOOLEAN STB_CiCcSendPin(U8BIT slot_id, U8BIT *pin_data)
874 {
875  BOOLEAN retval;
876  S_SLOT_STATE *slot_state;
877 
878  FUNCTION_START(STB_CiCcSendPin);
879 
880  retval = FALSE;
881 
882  DBG_CC("(slot=%u, pin=\"%s\")", slot_id, pin_data)
883 
884  if (((slot_state = FindSlot(slot_id)) != NULL) &&
885  slot_state->pin_caps_received && (slot_state->pin_caps != STB_CI_PIN_CAPS_NONE))
886  {
887  slot_state->play_pin_sent = FALSE;
888  retval = STB_CISendPinCmd(slot_id, pin_data);
889  }
890 
891  FUNCTION_FINISH(STB_CiCcSendPin);
892 
893  return(retval);
894 }
895 
896 /*****************************************************************************
897  *
898  * Function Name: STB_CINotifyPinReply
899  *
900  * Description: This function is called by the CI+ stack to send a PIN
901  * status to the host. This function is called in response
902  * to the host calling STB_CISendPinCmd or STB_CISendPinPlayback.
903  *
904  * Parameters: slot_id - zero-based CI slot identifier (0, 1, ...)
905  * status - PIN code status
906  *
907  * Returns: Nothing
908  *
909  ****************************************************************************/
910 void STB_CINotifyPinReply(U8BIT slot_id, E_STB_CI_PIN_STATUS status)
911 {
912  S_SLOT_STATE *slot_state;
913 
914  FUNCTION_START(STB_CINotifyPinReply);
915 
916  DBG_CC("(slot=%u, status=%d)", slot_id, status)
917 
918  if ((slot_state = FindSlot(slot_id)) != NULL)
919  {
920  /* Notify the host of the PIN result */
921  if (slot_state->play_pin_sent)
922  {
923  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_PLAYBACK_PIN_STATUS,
924  &status, sizeof(E_STB_CI_PIN_STATUS));
925  }
926  else
927  {
928  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_PIN_STATUS,
929  &status, sizeof(E_STB_CI_PIN_STATUS));
930  }
931  }
932 
933  FUNCTION_FINISH(STB_CINotifyPinReply);
934 }
935 
936 /*****************************************************************************
937  *
938  * Function Name: STB_CINotifyPinEvent
939  *
940  * Description: This function is called by the CI+ stack to send a PIN
941  * event to the host. This function is called when PIN
942  * requirements change and to acknowledge the PIN code.
943  *
944  * Parameters: slot_id - zero-based CI slot identifier (0, 1, ...)
945  * program_number - program number
946  * status - PIN code status
947  * rating - age rating of new program (3+rating=age)
948  * event_date - date of event
949  * event_time - time of event
950  * private_data - event private data (15 bytes)
951  *
952  * Returns: Nothing
953  *
954  ****************************************************************************/
955 void STB_CINotifyPinEvent(U8BIT slot_id, U16BIT program_number,
956  E_STB_CI_PIN_STATUS status, U8BIT rating,
957  S_STB_CI_DATE *event_date, S_STB_CI_TIME *event_time,
958  U8BIT private_data[CIP_PIN_PRIVATE_DATA_SIZE])
959 {
960  S_SLOT_STATE *slot_state;
961 
962  FUNCTION_START(STB_CINotifyPinEvent);
963 
964  DBG_CC("(slot=%u, program=%u, status=%u, date=%u/%u/%u, time=%u:%02u:%02u, rating=%u)",
965  slot_id, program_number, status, event_date->day, event_date->month,
966  event_date->year, event_time->hour, event_time->minute, event_time->second, rating)
967 
968  if ((slot_state = FindSlot(slot_id)) != NULL)
969  {
970  /* Only handle pin events for the service being recorded */
971  if (slot_state->recording && (program_number == slot_state->record_service_id))
972  {
973  /* Save the rating and private data so they can be requested for saving with the recording
974  * and send an event to notify the host */
975  slot_state->record_pin_status = status;
976  slot_state->record_age_rating = rating;
977  slot_state->pin_event_date = *event_date;
978  slot_state->pin_event_time = *event_time;
979  memcpy(slot_state->record_private_data, private_data, CIP_PIN_PRIVATE_DATA_SIZE);
980 
981  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_RECORD_PIN, &slot_id, sizeof(slot_id));
982  }
983  }
984 
985  FUNCTION_FINISH(STB_CINotifyPinEvent);
986 }
987 
1000 BOOLEAN STB_CiCcGetRecordingPinInfo(U8BIT slot_id, U8BIT *status, U8BIT *age_rating,
1001  U8BIT **private_data, U16BIT *date_code, U8BIT *hour, U8BIT *min, U8BIT *sec)
1002 {
1003  BOOLEAN retval;
1004  S_SLOT_STATE *slot_state;
1005 
1006  FUNCTION_START(STB_CiCcGetRecordingPinInfo);
1007 
1008  retval = FALSE;
1009 
1010  if ((slot_state = FindSlot(slot_id)) != NULL)
1011  {
1012  if (slot_state->recording)
1013  {
1014  *status = slot_state->record_pin_status;
1015  *age_rating = slot_state->record_age_rating;
1016  *private_data = slot_state->record_private_data;
1017  *date_code = slot_state->pin_event_date.mjd;
1018  *hour = slot_state->pin_event_time.hour;
1019  *min = slot_state->pin_event_time.minute;
1020  *sec = slot_state->pin_event_time.second;
1021  retval = TRUE;
1022  }
1023  }
1024 
1025  FUNCTION_FINISH(STB_CiCcGetRecordingPinInfo);
1026 
1027  return(retval);
1028 }
1029 
1037 BOOLEAN STB_CiCcSendPinPlayback(U8BIT slot_id, U8BIT age_rating, U8BIT *private_data)
1038 {
1039  BOOLEAN retval;
1040  S_SLOT_STATE *slot_state;
1041 
1042  FUNCTION_START(STB_CiCcSendPinPlayback);
1043 
1044  retval = FALSE;
1045 
1046  DBG_REC("%s(slot=%u, age=%u)", __FUNCTION__, slot_id, age_rating)
1047 
1048  if ((slot_state = FindSlot(slot_id)) != NULL)
1049  {
1050  slot_state->play_pin_sent = TRUE;
1051  retval = STB_CISendPinPlayback(slot_id, age_rating, private_data);
1052  }
1053 
1054  FUNCTION_FINISH(STB_CiCcSendPinPlayback);
1055 
1056  return(retval);
1057 }
1058 
1065 void STB_CiCcSetRecordOperatingMode(U8BIT slot_id, U32BIT mode, U16BIT service_id)
1066 {//E_STB_CI_OPERATING_MODE
1067  S_SLOT_STATE *slot_state;
1068 
1069  FUNCTION_START(STB_CiCcSetRecordOperatingMode);
1070 
1071  DBG_REC("%s(slot=%u, mode=%s, service_id=%u)", __FUNCTION__, slot_id,
1072  ((mode == STB_CI_MODE_WATCH_AND_BUFFER) ? "WATCH_AND_BUFFER" :
1073  (mode == STB_CI_MODE_TIMESHIFT) ? "TIMESHIFT" :
1074  (mode == STB_CI_MODE_UNATTENDED_RECORDING) ? "UNATTENDED" : "UNKNOWN!"), service_id)
1075 
1076  if (mode <= STB_CI_MODE_UNATTENDED_RECORDING)
1077  {
1078  if ((slot_state = FindSlot(slot_id)) != NULL)
1079  {
1080  /* Only need to do this for CI+ v1.3 and above */
1081  if ((STB_CIGetContentControlVersion(slot_id) >= 2) &&
1082  (!slot_state->op_mode_set || (mode != slot_state->operating_mode)))
1083  {
1084  DBG_REC("%s: Current mode %s", __FUNCTION__,
1085  ((slot_state->operating_mode == STB_CI_MODE_WATCH_AND_BUFFER) ? "WATCH_AND_BUFFER" :
1086  (slot_state->operating_mode == STB_CI_MODE_TIMESHIFT) ? "TIMESHIFT" :
1087  (slot_state->operating_mode == STB_CI_MODE_UNATTENDED_RECORDING) ? "UNATTENDED" : "UNKNOWN!"))
1088 
1089  /* Inform the CAM about the change of mode */
1090  if (slot_state->recording == TRUE)
1091  {
1092  slot_state->op_mode_set = STB_CIChangeOperatingMode(slot_id, mode, service_id);
1093  }
1094  }
1095 
1096  slot_state->operating_mode = mode;
1097  }
1098  }
1099 
1100  FUNCTION_FINISH(STB_CiCcSetRecordOperatingMode);
1101 }
1102 
1110 BOOLEAN STB_CiCcSendRecordStart(U8BIT slot_id, U16BIT program_number, U8BIT *pin_string)
1111 {
1112  S_SLOT_STATE *slot_state;
1113  BOOLEAN retval;
1114  FUNCTION_START(STB_CiCcSendRecordStart);
1115 
1116  retval = FALSE;
1117 
1118  DBG_REC("%s(slot=%u, program=%u, pin=\"%s\")", __FUNCTION__, slot_id, program_number, pin_string)
1119 
1120  if ((slot_state = FindSlot(slot_id)) != NULL)
1121  {
1122  slot_state->recording = TRUE;
1123  slot_state->record_service_id = program_number;
1124 
1125  /* Only need to do this for CI+ v1.3 and above */
1126  if ((STB_CIGetContentControlVersion(slot_id) >= 2) &&
1127  slot_state->pin_caps_received && (slot_state->pin_caps != STB_CI_PIN_CAPS_NONE))
1128  {
1129  DBG_REC("%s(%u): Asking CAM to start recording in %s mode using pin \"%s\"",
1130  __FUNCTION__, slot_id,
1131  ((slot_state->operating_mode == STB_CI_MODE_WATCH_AND_BUFFER) ? "WATCH_AND_BUFFER" :
1132  (slot_state->operating_mode == STB_CI_MODE_TIMESHIFT) ? "TIMESHIFT" :
1133  (slot_state->operating_mode == STB_CI_MODE_UNATTENDED_RECORDING) ? "UNATTENDED" : "UNKNOWN"),
1134  pin_string)
1135 
1136  retval = STB_CISendRecordStart(slot_id, slot_state->operating_mode, program_number, pin_string);
1137  if (!retval)
1138  {
1139  DBG_REC("%s(%u): Failed to send record start to CAM", __FUNCTION__, slot_id)
1140  slot_state->recording = FALSE;
1141  slot_state->record_service_id = 0xFFFF;
1142  }
1143  }
1144  else
1145  {
1146  /* The recording can be started */
1147  DBG_REC("%s(%u): No need to ask CAM, recording can start", __FUNCTION__, slot_id)
1148 
1149  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_RECORD_START, &slot_id, sizeof(slot_id));
1150  retval = TRUE;
1151  }
1152  }
1153 
1154  FUNCTION_FINISH(STB_CiCcSendRecordStart);
1155 
1156  return(retval);
1157 }
1158 
1173 void STB_CINotifyRecordStartStatus(U8BIT slot_id, U8BIT status)
1174 {
1175  FUNCTION_START(STB_CINotifyRecordStartStatus);
1176 
1177  DBG_REC("%s(slot=%u, status=%u)", __FUNCTION__, slot_id, status)
1178 
1179  if (status == STB_CI_CC_STATUS_OK)
1180  {
1181  /* The recording can be started */
1182  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_RECORD_START, &slot_id, sizeof(slot_id));
1183  }
1184  else
1185  {
1186  /* Recording shouldn't be started */
1187  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_RECORD_START_FAILED, &slot_id, sizeof(slot_id));
1188  }
1189 
1190  FUNCTION_FINISH(STB_CINotifyRecordStartStatus);
1191 }
1192 
1217 void STB_CINotifyRecordingLicense(U8BIT slot_id, U16BIT program_number,
1218  U8BIT licence_status, S_STB_CI_URI *uri,
1219  U8BIT *licence, U16BIT licence_len)
1220 {
1221  S_SLOT_STATE *slot_state;
1222 
1223  FUNCTION_START(STB_CINotifyRecordingLicense);
1224 
1225  USE_UNWANTED_PARAM(licence_status);
1226 
1227  DBG_REC("%s(slot=%u, program=%u, licence_status=%u, uri=%p, licence=%p, licence_len=%u)",
1228  __FUNCTION__, slot_id, program_number, licence_status, uri, licence, licence_len)
1229 
1230  if ((slot_state = FindSlot(slot_id)) != NULL)
1231  {
1232  if (slot_state->recording && (slot_state->record_service_id == program_number))
1233  {
1234  /* Save the URI so it can be requested by the host */
1235  slot_state->recording_uri = *uri;
1236 
1237  if ((slot_state->recording_licence != NULL) &&
1238  (slot_state->recording_licence_len != licence_len))
1239  {
1240  /* Licence length has changed so free the current one */
1241  STB_FreeMemory(slot_state->recording_licence);
1242  slot_state->recording_licence = NULL;
1243  slot_state->recording_licence_len = 0;
1244  }
1245 
1246  /* Save the licence and inform the host of the licence update */
1247  if (slot_state->recording_licence == NULL)
1248  {
1249  if ((slot_state->recording_licence = STB_GetMemory(licence_len)) != NULL)
1250  {
1251  slot_state->recording_licence_len = licence_len;
1252  }
1253  }
1254 
1255  if (slot_state->recording_licence != NULL)
1256  {
1257  slot_state->recording_licence_status = licence_status;
1258 
1259  memcpy(slot_state->recording_licence, licence, licence_len);
1260 
1261  /* Inform the host of the licence update */
1262  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_RECORD_LICENCE_UPDATED, &slot_id,
1263  sizeof(slot_id));
1264  }
1265  }
1266 #ifdef DEBUG_REC
1267  else
1268  {
1269  if (!slot_state->recording)
1270  {
1271  DBG_REC("%s(%u): Slot isn't being used for recording", __FUNCTION__, slot_id)
1272  }
1273  else
1274  {
1275  DBG_REC("%s(%u): Slot is recording program %u", __FUNCTION__, slot_id, slot_state->record_service_id)
1276  }
1277  }
1278 #endif
1279  }
1280 
1281  FUNCTION_FINISH(STB_CINotifyRecordingLicense);
1282 }
1283 
1292 U8BIT* STB_CiCcGetRecordingLicence(U8BIT slot_id, U8BIT *licence_status, U16BIT *licence_len,
1293  U8BIT raw_uri[CIP_URI_LEN])
1294 {
1295  U8BIT *licence;
1296  S_SLOT_STATE *slot_state;
1297 
1298  FUNCTION_START(STB_CiCcGetRecordingLicence);
1299 
1300  licence = NULL;
1301 
1302  if ((slot_state = FindSlot(slot_id)) != NULL)
1303  {
1304  licence = slot_state->recording_licence;
1305  *licence_status = slot_state->recording_licence_status;
1306  *licence_len = slot_state->recording_licence_len;
1307  PackUri(&slot_state->recording_uri, raw_uri);
1308  }
1309 
1310  FUNCTION_FINISH(STB_CiCcGetRecordingLicence);
1311 
1312  return(licence);
1313 }
1314 
1324 BOOLEAN STB_CiCcSendPlaybackLicence(U8BIT slot_id, U16BIT program_number, U8BIT *licence,
1325  U16BIT licence_len)
1326 {
1327  BOOLEAN retval;
1328  S_SLOT_STATE *slot_state;
1329 
1330  FUNCTION_START(STB_CiCcSendPlaybackLicence);
1331 
1332  DBG_REC("%s(slot=%u, program=%u, licence=%p, licence_len=%u)", __FUNCTION__, slot_id,
1333  program_number, licence, licence_len)
1334 
1335  retval = FALSE;
1336 
1337  if ((slot_state = FindSlot(slot_id)) != NULL)
1338  {
1339  slot_state->play_service_id = program_number;
1340  retval = STB_CISendPlaybackLicense(slot_id, program_number, licence, licence_len);
1341  if (!retval)
1342  {
1343  slot_state->play_service_id = 0xFFFF;
1344  DBG_REC("%s(%u): Failed to send playback licence", __FUNCTION__, slot_id)
1345  }
1346  }
1347 
1348  FUNCTION_FINISH(STB_CiCcSendPlaybackLicence);
1349 
1350  return(retval);
1351 }
1352 
1377 void STB_CINotifyPlaybackLicense(U8BIT slot_id, U16BIT program_number,
1378  U8BIT licence_status, S_STB_CI_URI *uri,
1379  U8BIT *licence, U16BIT licence_len)
1380 {
1381  S_SLOT_STATE *slot_state;
1382 
1383  FUNCTION_START(STB_CINotifyPlaybackLicense);
1384 
1385  USE_UNWANTED_PARAM(licence_status);
1386 
1387  DBG_REC("%s(slot=%u, program=%u, licence_status=%u, uri=%p, licence=%p, licence_len=%u)",
1388  __FUNCTION__, slot_id, program_number, licence_status, uri, licence, licence_len)
1389 
1390  if ((slot_state = FindSlot(slot_id)) != NULL)
1391  {
1392  if (slot_state->play_service_id == program_number)
1393  {
1394  /* Save the URI so it can be requested by the host */
1395  slot_state->playback_uri = *uri;
1396 
1397  if ((slot_state->playback_licence != NULL) &&
1398  (slot_state->playback_licence_len != licence_len))
1399  {
1400  /* Licence length has changed so free the current one */
1401  STB_FreeMemory(slot_state->playback_licence);
1402  slot_state->playback_licence = NULL;
1403  slot_state->playback_licence_len = 0;
1404  }
1405 
1406  /* Save the licence and inform the host of the licence update */
1407  if (slot_state->playback_licence == NULL)
1408  {
1409  if ((slot_state->playback_licence = STB_GetMemory(licence_len)) != NULL)
1410  {
1411  slot_state->playback_licence_len = licence_len;
1412  }
1413  }
1414 
1415  if (slot_state->playback_licence != NULL)
1416  {
1417  slot_state->playback_licence_status = licence_status;
1418 
1419  memcpy(slot_state->playback_licence, licence, licence_len);
1420 
1421  /* Inform the host of the licence update */
1422  STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CI, EV_TYPE_CI_PLAYBACK_LICENCE_UPDATED, &slot_id,
1423  sizeof(slot_id));
1424  }
1425  }
1426  else
1427  {
1428  DBG_REC("%s(%u): Slot is playing program %u", __FUNCTION__, slot_id, slot_state->play_service_id)
1429  }
1430  }
1431 
1432  FUNCTION_FINISH(STB_CINotifyPlaybackLicense);
1433 }
1434 
1443 U8BIT* STB_CiCcGetPlaybackLicence(U8BIT slot_id, U8BIT *licence_status, U16BIT *licence_len,
1444  U8BIT raw_uri[CIP_URI_LEN])
1445 {
1446  U8BIT *licence;
1447  S_SLOT_STATE *slot_state;
1448 
1449  FUNCTION_START(STB_CiCcGetPlaybackLicence);
1450 
1451  licence = NULL;
1452 
1453  if ((slot_state = FindSlot(slot_id)) != NULL)
1454  {
1455  licence = slot_state->playback_licence;
1456  *licence_status = slot_state->playback_licence_status;
1457  *licence_len = slot_state->playback_licence_len;
1458  PackUri(&slot_state->playback_uri, raw_uri);
1459  }
1460 
1461  FUNCTION_FINISH(STB_CiCcGetPlaybackLicence);
1462 
1463  return(licence);
1464 }
1465 
1484 void STB_CINotifyLicenseStatus(U8BIT slot_id, U8BIT licence_status, U8BIT play_count)
1485 {
1486  FUNCTION_START(STB_CINotifyLicenseStatus);
1487 
1488  DBG_REC("%s(slot=%u, licence_status=%u, play_count=%u)", __FUNCTION__, slot_id, licence_status,
1489  play_count)
1490 
1491  USE_UNWANTED_PARAM(slot_id);
1492  USE_UNWANTED_PARAM(licence_status);
1493  USE_UNWANTED_PARAM(play_count);
1494 
1495  FUNCTION_FINISH(STB_CINotifyLicenseStatus);
1496 }
1497 
1512 void STB_CINotifyModeChangeStatus(U8BIT slot_id, U8BIT status)
1513 {
1514  FUNCTION_START(STB_CINotifyModeChangeStatus);
1515 
1516  DBG_REC("%s(slot=%u, status=%u)", __FUNCTION__, slot_id, status)
1517 
1518  USE_UNWANTED_PARAM(slot_id);
1519  USE_UNWANTED_PARAM(status);
1520 
1521  FUNCTION_FINISH(STB_CINotifyModeChangeStatus);
1522 }
1523 
1529 BOOLEAN STB_CiCcSendRecordStop(U8BIT slot_id)
1530 {
1531  BOOLEAN retval;
1532  S_SLOT_STATE *slot_state;
1533 
1534  FUNCTION_START(STB_CiCcSendRecordStop);
1535 
1536  retval = FALSE;
1537 
1538  DBG_REC("%s(slot=%u)", __FUNCTION__, slot_id)
1539 
1540  if ((slot_state = FindSlot(slot_id)) != NULL)
1541  {
1542  if (slot_state->recording)
1543  {
1544  if ((STB_CIGetContentControlVersion(slot_id) >= 2) &&
1545  slot_state->pin_caps_received && (slot_state->pin_caps != STB_CI_PIN_CAPS_NONE))
1546  {
1547  DBG_REC("%s(%u): Sending record stop to CAM", __FUNCTION__, slot_id)
1548 
1549  /* Inform the CAM that the recording has stopped */
1550  retval = STB_CISendRecordStop(slot_id, slot_state->record_service_id);
1551 #ifdef DEBUG_REC
1552  if (!retval)
1553  {
1554  DBG_REC("%s(%u): Failed to send record stop to CAM", __FUNCTION__, slot_id)
1555  }
1556 #endif
1557  }
1558  else
1559  {
1560  DBG_REC("%s(%u): No need to inform CAM", __FUNCTION__, slot_id)
1561  retval = TRUE;
1562  }
1563 
1564  slot_state->recording = FALSE;
1565  }
1566  }
1567 
1568  FUNCTION_FINISH(STB_CiCcSendRecordStop);
1569 
1570  return(retval);
1571 }
1572 
1587 void STB_CINotifyRecordStopStatus(U8BIT slot_id, U8BIT status)
1588 {
1589  FUNCTION_START(STB_CINotifyRecordStopStatus);
1590 
1591  DBG_REC("%s(slot=%u, status=%u)", __FUNCTION__, slot_id, status)
1592 
1593  USE_UNWANTED_PARAM(slot_id);
1594  USE_UNWANTED_PARAM(status);
1595 
1596  FUNCTION_FINISH(STB_CINotifyRecordStopStatus);
1597 }
1598 
1599 
1600 /*---local function definitions----------------------------------------------*/
1601 
1602 static S_SLOT_STATE *FindSlot(U8BIT slot_id)
1603 {
1604  S_SLOT_STATE *slot_info;
1605  STB_OSMutexLock(cicc_mutex);
1606  slot_info = cicc_slots;
1607  while (slot_info != NULL)
1608  {
1609  if (slot_info->slot_id == slot_id)
1610  {
1611  if (slot_info->disabled)
1612  {
1613  slot_info = NULL;
1614  }
1615  break;
1616  }
1617  slot_info = slot_info->next;
1618  }
1619  STB_OSMutexUnlock(cicc_mutex);
1620  return slot_info;
1621 }
1622 
1633 static BOOLEAN IsServiceAllowed(S_SLOT_STATE *slot_state,
1634  U8BIT *ci_protection_descriptor)
1635 {
1636  BOOLEAN allowed;
1637  U8BIT i;
1638 
1639  FUNCTION_START(IsServiceAllowed);
1640 
1641  allowed = FALSE;
1642 
1643  if (ci_protection_info.sdt_acquisition_complete)
1644  {
1645  ParseCiProtectionDescriptor(ci_protection_descriptor);
1646  if (ci_protection_info.free_ci_mode_flag == FALSE)
1647  {
1648  /* No restriction */
1649  DBGPRINT("free_ci_mode_flag == FALSE: allowed = TRUE")
1650  allowed = TRUE;
1651  }
1652  else if (slot_state->auth_status == CI_AUTH_SUCCESS)
1653  {
1654  if (ci_protection_info.match_brand_flag == FALSE)
1655  {
1656  /* CI+ only, but no brand ID matching */
1657  DBGPRINT("CI+ only, no brand matching, authenticated: allowed = TRUE")
1658  allowed = TRUE;
1659  }
1660  else
1661  {
1662  for (i = 0; i < ci_protection_info.number_of_entries; i++)
1663  {
1664  if (slot_state->cicam_brand_id == ci_protection_info.entries[i])
1665  {
1666  /* Found CICAM brand match */
1667  DBGPRINT("CI+ only, brand found: allowed = TRUE")
1668  allowed = TRUE;
1669  break;
1670  }
1671  }
1672  }
1673  }
1674  }
1675 
1676  if (!allowed)
1677  {
1678  DBGPRINT("allowed = FALSE")
1679  }
1680 
1681  FUNCTION_FINISH(IsServiceAllowed);
1682 
1683  return allowed;
1684 }
1685 
1691 static void ParseCiProtectionDescriptor(U8BIT *ci_protection_descriptor)
1692 {
1693  U8BIT *d;
1694  U8BIT tag;
1695  U8BIT len;
1696  U8BIT number_of_entries;
1697  U16BIT offset;
1698  U16BIT *entry;
1699 
1700  FUNCTION_START(ParseCiProtectionDescriptor);
1701 
1702  if (ci_protection_descriptor == NULL)
1703  {
1704  /* No descriptor = no restriction */
1705  DBGPRINT("ci_protection_descriptor == NULL: no restriction")
1706  ci_protection_info.free_ci_mode_flag = FALSE;
1707  ci_protection_info.match_brand_flag = FALSE;
1708  ci_protection_info.number_of_entries = 0;
1709  }
1710  else
1711  {
1712  /* We assume that the descriptor is valid */
1713  d = ci_protection_descriptor;
1714  tag = d[0];
1715  len = d[1];
1716 
1717  DBGPRINT("ci_protection_descriptor: tag=%x, len=%d", tag, len)
1718 
1719  ci_protection_info.free_ci_mode_flag = TRUE;
1720  ci_protection_info.match_brand_flag = TRUE;
1721  ci_protection_info.number_of_entries = 0;
1722 
1723  if (tag == 0xCE && len >= 1)
1724  {
1725  DBGPRINT("d2=%x", d[2])
1726  if (((d[2] >> 7) & 0x1) == 0x0)
1727  {
1728  ci_protection_info.free_ci_mode_flag = FALSE;
1729  }
1730  else
1731  {
1732  ci_protection_info.free_ci_mode_flag = TRUE;
1733  }
1734 
1735  if (((d[2] >> 6) & 0x1) == 0x0)
1736  {
1737  ci_protection_info.match_brand_flag = FALSE;
1738  }
1739  else
1740  {
1741  ci_protection_info.match_brand_flag = TRUE;
1742  ci_protection_info.number_of_entries = 0;
1743 
1744  /* Service requires CI+ protection */
1745  if (len >= 2)
1746  {
1747  /* Parse valid brands (as much as possible) */
1748  number_of_entries = d[3];
1749  DBGPRINT("number_of_entries = %d", number_of_entries)
1750  entry = ci_protection_info.entries;
1751  offset = 2;
1752  while (ci_protection_info.number_of_entries < number_of_entries &&
1753  offset + 1 < len)
1754  {
1755  *entry = d[2 + offset] << 8 | d[2 + offset + 1];
1756  DBGPRINT("entry: %04x", *entry)
1757  ci_protection_info.number_of_entries++;
1758  entry++;
1759  offset += 2;
1760  }
1761  }
1762  }
1763  }
1764  }
1765 
1766  FUNCTION_FINISH(ParseCiProtectionDescriptor);
1767 }
1768 
1775 static void ApplyURIv1(S_STB_CI_URI *uri, BOOLEAN playback)
1776 {
1777  U8BIT aps, emi, rct, ict;
1779 
1780  memset(&cp, 0, sizeof cp);
1781 
1782  /* If URI is NULL, copy protection is not required */
1783  if (uri != NULL)
1784  {
1785  aps = uri->aps_copy_control_info;
1786  emi = uri->emi_copy_control_info;
1787  rct = uri->rct_copy_control_info;
1788  ict = uri->ict_copy_control_info;
1789 
1790  /* Macrovision:
1791  * If rct=1 and/or emi=01,10,11, the value should be aps */
1792  cp.macrovision_set = TRUE;
1793  cp.macrovision = ((rct || emi) * 3) & aps;
1794 
1795  /* APS = Analog Protection System
1796  * If emi=01,10,11, the value should be aps */
1797  cp.aps_set = TRUE;
1798  cp.aps = ((emi != 0) * 3) & aps;
1799 
1800  /* CGMS-A = Copy Generation Management System - Analog */
1801  cp.cgms_a_set = TRUE;
1802  cp.cgms_a = emi;
1803 
1804  /* Note 6 in ILA */
1805  if ((rct == 0) && (emi == 0x2))
1806  {
1807  if (playback)
1808  {
1809  /* Macrovision is active, CGMS-A is "copy no more" */
1810  cp.cgms_a = 0x1;
1811  }
1812  else
1813  {
1814  /* Macrovision is inctive, CGMS-A is "copy once" */
1815  cp.macrovision = 0;
1816  }
1817  }
1818 
1819  /* Image constraint */
1820  cp.ict_set = TRUE;
1821  cp.ict = ict;
1822 
1823  /* HDCP */
1824  cp.hdcp_set = TRUE;
1825  cp.hdcp = TRUE;
1826 
1827  /* SCMS */
1828  cp.scms_set = TRUE;
1829  if (emi == 0)
1830  {
1831  cp.scms = 0x2;
1832  }
1833  else
1834  {
1835  cp.scms = emi & 0x1;
1836  }
1837 
1838  /* DOT */
1839  cp.dot_set = FALSE;
1840  }
1841 
1843 }
1844 
1851 static void ApplyURIv2(S_STB_CI_URI *uri, BOOLEAN playback)
1852 {
1853  U8BIT aps, emi, rct, ict;
1855 
1856  memset(&cp, 0, sizeof cp);
1857 
1858  /* If URI is NULL, copy protection is not required */
1859  if (uri != NULL)
1860  {
1861  aps = uri->aps_copy_control_info;
1862  emi = uri->emi_copy_control_info;
1863  rct = uri->rct_copy_control_info;
1864  ict = uri->ict_copy_control_info;
1865 
1866  /* Macrovision:
1867  * If rct=1 and/or emi=01,10,11, the value should be aps */
1868  cp.macrovision_set = TRUE;
1869  cp.macrovision = ((rct || emi) * 3) & aps;
1870 
1871  /* APS = Analog Protection System
1872  * If emi=01,10,11, the value should be aps */
1873  cp.aps_set = TRUE;
1874  cp.aps = ((emi != 0) * 3) & aps;
1875 
1876  /* CGMS-A = Copy Generation Management System - Analog */
1877  cp.cgms_a_set = TRUE;
1878  cp.cgms_a = emi;
1879 
1880  /* Note 6 in ILA */
1881  if ((rct == 0) && (emi == 0x2))
1882  {
1883  if (playback)
1884  {
1885  /* Macrovision is active, CGMS-A is "copy no more" */
1886  cp.cgms_a = 0x1;
1887  }
1888  else
1889  {
1890  /* Macrovision is inctive, CGMS-A is "copy once" */
1891  cp.macrovision = 0;
1892  }
1893  }
1894 
1895  /* Image constraint */
1896  cp.ict_set = TRUE;
1897  cp.ict = ict;
1898 
1899  /* HDCP */
1900  cp.hdcp_set = TRUE;
1901  cp.hdcp = TRUE;
1902 
1903  /* SCMS */
1904  cp.scms_set = TRUE;
1905  if (emi == 0)
1906  {
1907  cp.scms = 0x2;
1908  }
1909  else
1910  {
1911  cp.scms = emi & 0x1;
1912  }
1913 
1914  /* DOT */
1915  cp.dot_set = TRUE;
1916  cp.dot = uri->dot_copy_control_info;
1917  }
1918 
1920 }
1921 
1926 static void ApplyInvalidURI(void)
1927 {
1929 
1930  memset(&cp, 0, sizeof cp);
1932 }
1933 
1940 static void PackUri(S_STB_CI_URI *uri, U8BIT buffer[CIP_URI_LEN])
1941 {
1942  FUNCTION_START(PackUri);
1943 
1944  memset(buffer, 0x00, CIP_URI_LEN);
1945 
1946  if (uri != NULL)
1947  {
1948  if (uri->protocol_version == 0x01)
1949  {
1950  /* protocol_version */
1951  buffer[0] = 0x01;
1952 
1953  buffer[1] |= (uri->aps_copy_control_info & 0x3) << 6;
1954  buffer[1] |= (uri->emi_copy_control_info & 0x3) << 4;
1955  buffer[1] |= (uri->ict_copy_control_info & 0x1) << 3;
1956  buffer[1] |= (uri->rct_copy_control_info & 0x1) << 2;
1957  buffer[1] |= 0x3;
1958 
1959  buffer[2] |= 0xc0 << 6;
1960  buffer[2] |= (uri->rl_copy_control_info & 0x3f);
1961 
1962  /* reserved */
1963  buffer[3] = buffer[4] = buffer[5] = buffer[6] = buffer[7] = 0xff;
1964  }
1965  else if (uri->protocol_version == 0x02)
1966  {
1967  /* protocol_version */
1968  buffer[0] = 0x02;
1969 
1970  buffer[1] |= (uri->aps_copy_control_info & 0x3) << 6;
1971  buffer[1] |= (uri->emi_copy_control_info & 0x3) << 4;
1972  buffer[1] |= (uri->ict_copy_control_info & 0x1) << 3;
1973 
1974  if ((uri->emi_copy_control_info & 0x03) == 0x00)
1975  {
1976  buffer[1] |= (uri->rct_copy_control_info & 0x1) << 2;
1977  }
1978 
1979  /* reserved bit */
1980  buffer[1] |= 0x2;
1981 
1982  if ((uri->emi_copy_control_info & 0x03) == 0x03)
1983  {
1984  buffer[1] |= (uri->dot_copy_control_info & 0x01);
1985  buffer[2] = uri->rl_copy_control_info & 0xfe;
1986  }
1987 
1988  /* reserved */
1989  buffer[3] = buffer[4] = buffer[5] = buffer[6] = buffer[7] = 0xff;
1990  }
1991  }
1992 
1993  FUNCTION_FINISH(PackUri);
1994 }
1995 
2002 static void UnpackUri(U8BIT buffer[CIP_URI_LEN], S_STB_CI_URI *uri)
2003 {
2004  FUNCTION_START(UnpackUri);
2005 
2006  if (buffer[0] == 0x01)
2007  {
2008  /* Assume URI v1 */
2009  uri->protocol_version = buffer[0];
2010 
2011  uri->aps_copy_control_info = (buffer[1] >> 6) & 0x3;
2012  uri->emi_copy_control_info = (buffer[1] >> 4) & 0x3;
2013  uri->ict_copy_control_info = (buffer[1] >> 3) & 0x1;
2014  uri->rct_copy_control_info = (buffer[1] >> 2) & 0x1;
2015 
2016  uri->rl_copy_control_info = buffer[2] & 0x3f;
2017  }
2018  else if (buffer[0] == 0x02)
2019  {
2020  /* URI v2 */
2021  uri->protocol_version = buffer[0];
2022 
2023  uri->aps_copy_control_info = (buffer[1] >> 6) & 0x3;
2024  uri->emi_copy_control_info = (buffer[1] >> 4) & 0x3;
2025  uri->ict_copy_control_info = (buffer[1] >> 3) & 0x1;
2026  uri->rct_copy_control_info = (buffer[1] >> 2) & 0x1;
2027  uri->dot_copy_control_info = buffer[1] & 0x1;
2028 
2029  uri->rl_copy_control_info = buffer[2] & 0xfe;
2030  }
2031  else
2032  {
2033  /* Invalid URI */
2034  uri->protocol_version = 0x00;
2035  }
2036 
2037  FUNCTION_FINISH(UnpackUri);
2038 }
2039 
void STB_CiCcSetRecordOperatingMode(U8BIT slot_id, U32BIT mode, U16BIT service_id)
Sets the record operating mode for the given slot id.
Definition: stbcicc.c:1065
BOOLEAN STB_CiCcSendRecordStop(U8BIT slot_id)
Called by the app when a recording is stopped or completes.
Definition: stbcicc.c:1529
U8BIT * STB_CiCcGetPlaybackLicence(U8BIT slot_id, U8BIT *licence_status, U16BIT *licence_len, U8BIT raw_uri[CIP_URI_LEN])
Returns the last licence received from the CAM during playback.
Definition: stbcicc.c:1443
void STB_CiKeysDisable(U8BIT slot_id)
Disable CC keys for slot, as CAM is being removed.
Definition: stbcikeys.c:113
void STB_CINotifyURI(U8BIT slot_id, U16BIT program_number, S_STB_CI_URI *uri)
Handle URI (usage rules information)
Definition: stbcicc.c:738
U8BIT * STB_CiCcGetRecordingLicence(U8BIT slot_id, U8BIT *licence_status, U16BIT *licence_len, U8BIT raw_uri[CIP_URI_LEN])
Returns the last licence received from the CAM when recording.
Definition: stbcicc.c:1292
void * STB_GetMemory(U32BIT bytes)
Attempts to allocate memory from the heap.
Definition: stbheap.c:221
BOOLEAN STB_CiCcSendPin(U8BIT slot_id, U8BIT *pin_data)
Called by the host to check whether a CAM pin is valid. An STB_EVENT_CI_PIN_STATUS event will be sent...
Definition: stbcicc.c:873
BOOLEAN STB_CiCcSendRecordStart(U8BIT slot_id, U16BIT program_number, U8BIT *pin_string)
Called by the app when a recording is to be started on a CA protected service.
Definition: stbcicc.c:1110
void STB_CiCcNotifyModuleRemove(U8BIT slot_id)
Notify module removal.
Definition: stbcicc.c:249
void STB_CiCcApplyUsageRulesInfoForPlayback(U8BIT *raw_uri)
Apply the given Usage Rules Information for playback.
Definition: stbcicc.c:578
BOOLEAN STB_CiCcGetRecordingPinInfo(U8BIT slot_id, U8BIT *status, U8BIT *age_rating, U8BIT **private_data, U16BIT *date_code, U8BIT *hour, U8BIT *min, U8BIT *sec)
Returns the information to be stored with a pin event when recording.
Definition: stbcicc.c:1000
Header file - macros and function prototypes for public use.
void STB_CINotifyRecordStartStatus(U8BIT slot_id, U8BIT status)
Definition: stbcicc.c:1173
void STB_CINotifyRecordStopStatus(U8BIT slot_id, U8BIT status)
Definition: stbcicc.c:1587
BOOLEAN STB_CiCcAuthenticated(U8BIT slot_id)
Tell whether the CI slot has been authenticated.
Definition: stbcicc.c:374
BOOLEAN STB_CiCcIsHDCPRequired(U16BIT service_id)
Tell whether the given service requires HDCP.
Definition: stbcicc.c:609
Header file - Function prototypes for A/V control.
U32BIT STB_CiCcGetRetentionLimit(U8BIT raw_uri[CIP_URI_LEN])
Return the retention limit given a packed URI.
Definition: stbcicc.c:495
BOOLEAN STB_CiCcIsSlotReady(U8BIT slot_id)
Return whether CI slot is ready.
Definition: stbcicc.c:319
void STB_OSMutexUnlock(void *mutex)
Unlock a mutex (a.k.a. &#39;leave&#39;, &#39;signal&#39; or &#39;release&#39;)
E_STB_AV_SRM_REPLY STB_AVApplySRM(U8BIT path, U8BIT *data, U32BIT len)
Apply System Renewability Message (SRM) to HDCP function.
void STB_ERSendEvent(BOOLEAN latched, BOOLEAN repeat, U16BIT path_class, U16BIT type, void *data, U32BIT data_size)
Sends an event to event reporting control module.
Definition: stberc.c:571
CI Content Control.
void STB_CINotifyModeChangeStatus(U8BIT slot_id, U8BIT status)
Definition: stbcicc.c:1512
void STB_CINotifyLicenseStatus(U8BIT slot_id, U8BIT licence_status, U8BIT play_count)
Definition: stbcicc.c:1484
U8BIT STB_DPGetLivePath(void)
Returns the ID of the decode path being used for live viewing.
Definition: stbdpc.c:1271
void STB_CiCcApplyUsageRulesInfo(U8BIT raw_uri[CIP_URI_LEN])
Apply the given Usage Rules Information.
Definition: stbcicc.c:547
void STB_CiCcGetDefaultUsageRulesInfo(U8BIT raw_uri[CIP_URI_LEN])
Sets the default URI values into the given array. The URI requires HDCP.
Definition: stbcicc.c:477
void STB_FreeMemory(void *addr)
Releases previously allocated heap memory.
Definition: stbheap.c:336
void STB_CiKeysInitialise(void)
CI descrambler keys support initialise.
Definition: stbcikeys.c:104
Debug functions header file.
BOOLEAN STB_CiCcIsServiceAllowed(U8BIT slot_id, U8BIT *ci_prot_desc)
Tell whether the service is allowed. This function checks whether the CI Protection Descriptor allows...
Definition: stbcicc.c:349
void STB_OSMutexLock(void *mutex)
Lock a mutex (a.k.a. &#39;enter&#39;, &#39;wait&#39; or &#39;get&#39;).
void STB_CiCaInitialise(void)
CI conditional access support initialise.
Definition: stbcica.c:84
U8BIT STB_DPGetPathTuner(U8BIT path)
Returns the tuner ID acquired by the given decode path.
Definition: stbdpc.c:1605
void STB_CINotifyModuleReady(U8BIT slot_id, BOOLEAN ci_plus, U32BIT mask)
Notify module insertion.
Definition: stbcicc.c:227
Header file - Function prototypes for Event Reporting.
void STB_CiKeysRemove(U8BIT slot_id)
Process CAM removal from slot for CI Keys support.
Definition: stbcikeys.c:133
CI Content Control support - internal header.
void STB_CINotifyPlaybackLicense(U8BIT slot_id, U16BIT program_number, U8BIT licence_status, S_STB_CI_URI *uri, U8BIT *licence, U16BIT licence_len)
Definition: stbcicc.c:1377
void STB_CiCaDisable(U8BIT slot_id)
Disable CA for slot, as CAM is being removed.
Definition: stbcica.c:93
Header file - Function prototypes for operating system.
System Wide Global Technical Data Type Definitions.
void STB_CiCaRemove(U8BIT slot_id)
Process CAM removal from slot for CA support.
Definition: stbcica.c:113
void STB_CiCcSetSDTAcquisitionStatus(BOOLEAN complete)
To implement the first part of the diagram in Figure 10.2: Shunning Operation of ci-plus_specificatio...
Definition: stbcicc.c:434
U8BIT STB_CiCcFindSlotForCicamId(U8BIT cicam_id[CIP_CICAM_ID_LEN])
Checks CAMs in all slots to find the one with the given CAM id.
Definition: stbcicc.c:399
Header file - Function prototypes for heap memory.
void * STB_OSCreateMutex(void)
Create a mutex.
void STB_CiCcNotifyModuleInsert(U8BIT slot_id)
Notify module insertion.
Definition: stbcicc.c:170
void STB_CINotifyProgress(U8BIT slot_id, E_STB_CI_CC_STATE state, U16BIT cicam_brand_id)
Notify content control progress.
Definition: stbcicc.c:649
void STB_CINotifyRecordingLicense(U8BIT slot_id, U16BIT program_number, U8BIT licence_status, S_STB_CI_URI *uri, U8BIT *licence, U16BIT licence_len)
Definition: stbcicc.c:1217
#define DBGPRINT(...)
Definition: dbgfuncs.h:74
void STB_CiCcRemove(U8BIT slot_id)
Handle CAM removal from slot.
Definition: stbcicc.c:275
U8BIT STB_CINotifySRM(U8BIT slot_id, E_STB_SRM_DATA_TYPE srm_type, U8BIT *data, U16BIT len)
This function is called by the CI+ stack to send an SRM (System Renewability Message) to the host...
Definition: stbcicc.c:779
BOOLEAN STB_CiCcSendPlaybackLicence(U8BIT slot_id, U16BIT program_number, U8BIT *licence, U16BIT licence_len)
Sends a CICAM licence to a module during playback, which will result in a modified licence being noti...
Definition: stbcicc.c:1324
void STB_CiCcGetUsageRulesInfo(U8BIT slot_id, U16BIT service_id, U8BIT raw_uri[CIP_URI_LEN])
Return the current URI for the given service.
Definition: stbcicc.c:449
void STB_CiCcInitialise(void)
CI content control support initialise.
Definition: stbcicc.c:159
BOOLEAN STB_CiCcSendPinPlayback(U8BIT slot_id, U8BIT age_rating, U8BIT *private_data)
Sends a pin event to the CAM during playback.
Definition: stbcicc.c:1037
void STB_AVSetCopyProtection(S_STB_AV_COPY_PROTECTION *copy_protection)
Apply the specified copy protection. This function is used for CI+.