1 #define MODULE_LOG_PREFIX "dvbstapi"
5 #if defined(HAVE_DVBAPI) && defined(WITH_STAPI)
7 #include "module-dvbapi.h"
8 #include "module-dvbapi-stapi.h"
9 #include "oscam-client.h"
10 #include "oscam-files.h"
11 #include "oscam-string.h"
12 #include "oscam-time.h"
14 extern int32_t exit_oscam
;
19 uint32_t SessionHandle
;
20 uint32_t SignalHandle
;
22 struct filter_s demux_fd
[MAX_DEMUX
][MAX_FILTER
];
25 struct read_thread_param
32 #define PROCDIR "/proc/stpti4_core/"
34 /* These functions are in liboscam_stapi.a */
35 extern uint32_t oscam_stapi_Capability(char *name
);
36 extern char *oscam_stapi_LibVersion(void);
37 extern uint32_t oscam_stapi_Open(char *name
, uint32_t *sessionhandle
);
38 extern uint32_t oscam_stapi_SignalAllocate(uint32_t sessionhandle
, uint32_t *signalhandle
);
39 extern uint32_t oscam_stapi_FilterAllocate(uint32_t sessionhandle
, uint32_t *filterhandle
);
40 extern uint32_t oscam_stapi_SlotInit(uint32_t sessionhandle
, uint32_t signalhandle
, uint32_t *bufferhandle
, uint32_t *slothandle
, uint16_t pid
);
41 extern uint32_t oscam_stapi_FilterSet(uint32_t filterhandle
, uint8_t *filt
, uint8_t *mask
);
42 extern uint32_t oscam_stapi_FilterAssociate(uint32_t filterhandle
, uint32_t slothandle
);
43 extern uint32_t oscam_stapi_SlotDeallocate(uint32_t slothandle
);
44 extern uint32_t oscam_stapi_BufferDeallocate(uint32_t bufferhandle
);
45 extern uint32_t oscam_stapi_FilterDeallocate(uint32_t filterhandle
);
46 extern uint32_t oscam_stapi_Close(uint32_t sessionhandle
);
47 extern uint32_t oscam_stapi_CheckVersion(void);
48 extern uint32_t oscam_stapi_DescramblerAssociate(uint32_t deschandle
, uint32_t slot
);
49 extern uint32_t oscam_stapi_DescramblerDisassociate(uint32_t deschandle
, uint32_t slot
);
50 extern uint32_t oscam_stapi_DescramblerAllocate(uint32_t sessionhandle
, uint32_t *deschandle
);
51 extern uint32_t oscam_stapi_DescramblerDeallocate(uint32_t deschandle
);
52 extern uint32_t oscam_stapi_DescramblerSet(uint32_t deschandle
, int32_t parity
, uint8_t *cw
);
53 extern uint32_t oscam_stapi_SignalWaitBuffer(uint32_t signalhandle
, uint32_t *qbuffer
, int32_t timeout
);
54 extern uint32_t oscam_stapi_BufferReadSection(uint32_t bufferhandle
, uint32_t *filterlist
, int32_t maxfilter
, uint32_t *filtercount
, int32_t *crc
, uint8_t *buf
, int32_t bufsize
, uint32_t *size
);
55 extern uint32_t oscam_stapi_SignalAbort(uint32_t signalhandle
);
56 extern uint32_t oscam_stapi_PidQuery(char *name
, uint16_t pid
);
57 extern uint32_t oscam_stapi_BufferFlush(uint32_t bufferhandle
);
58 extern uint32_t oscam_stapi_SlotClearPid(uint32_t slot
);
61 static void *stapi_read_thread(void *);
62 static int32_t stapi_do_set_filter(int32_t demux_id
, FILTERTYPE
*filter
, uint16_t *pids
, int32_t pidcount
, uint8_t *filt
, uint8_t *mask
, int32_t dev_id
);
63 static int32_t stapi_do_remove_filter(int32_t demux_id
, FILTERTYPE
*filter
, int32_t dev_id
);
65 // These variables are declared in module-dvbapi.c
66 extern int32_t disable_pmt_files
;
67 extern struct s_dvbapi_priority
*dvbapi_priority
;
68 extern DEMUXTYPE demux
[MAX_DEMUX
];
70 static int32_t stapi_on
;
71 static pthread_mutex_t filter_lock
;
72 static struct STDEVICE dev_list
[PTINUM
];
74 static void stapi_off(void)
78 SAFE_MUTEX_LOCK(&filter_lock
);
80 cs_log("stapi shutdown");
82 disable_pmt_files
= 1;
84 for(i
= 0; i
< MAX_DEMUX
; i
++)
86 dvbapi_stop_descrambling(i
, 0);
89 for(i
= 0; i
< PTINUM
; i
++)
91 if(dev_list
[i
].SessionHandle
> 0)
93 if(dev_list
[i
].SignalHandle
> 0)
95 oscam_stapi_SignalAbort(dev_list
[i
].SignalHandle
);
97 pthread_cancel(dev_list
[i
].thread
);
101 SAFE_MUTEX_UNLOCK(&filter_lock
);
106 int32_t stapi_open(void)
111 struct dirent entry
, *dp
= NULL
;
116 int32_t stapi_priority
= 0;
118 dirp
= opendir(PROCDIR
);
121 cs_log("opendir failed (errno=%d %s)", errno
, strerror(errno
));
125 memset(dev_list
, 0, sizeof(struct STDEVICE
)*PTINUM
);
126 memset(pfad
, 0, sizeof(pfad
));
130 struct s_dvbapi_priority
*p
;
131 for(p
= dvbapi_priority
; p
!= NULL
; p
= p
->next
)
143 cs_log("WARNING: no PTI devices defined, stapi disabled");
147 oscam_stapi_CheckVersion();
150 while(!cs_readdir_r(dirp
, &entry
, &dp
))
155 snprintf(pfad
, sizeof(pfad
), "%s%s", PROCDIR
, dp
->d_name
);
156 if(stat(pfad
, &buf
) != 0)
159 if(!(buf
.st_mode
& S_IFDIR
&& strncmp(dp
->d_name
, ".", 1) != 0))
163 struct s_dvbapi_priority
*p
;
165 for(p
= dvbapi_priority
; p
!= NULL
; p
= p
->next
)
167 if(p
->type
!= 's') { continue; }
168 if(strcmp(dp
->d_name
, p
->devname
) == 0)
177 cs_log("PTI: %s skipped", dp
->d_name
);
181 ErrorCode
= oscam_stapi_Open(dp
->d_name
, &dev_list
[i
].SessionHandle
);
184 cs_log("STPTI_Open ErrorCode: %d", ErrorCode
);
189 //oscam_stapi_Capability(dp->d_name);
191 cs_strncpy(dev_list
[i
].name
, dp
->d_name
, sizeof(dev_list
[i
].name
));
192 cs_log("PTI: %s open %d", dp
->d_name
, i
);
194 ErrorCode
= oscam_stapi_SignalAllocate(dev_list
[i
].SessionHandle
, &dev_list
[i
].SignalHandle
);
196 { cs_log("SignalAllocate: ErrorCode: %d SignalHandle: %x", ErrorCode
, dev_list
[i
].SignalHandle
); }
199 if(i
>= PTINUM
) { break; }
203 if(i
== 0) { return 0; }
205 SAFE_MUTEX_INIT(&filter_lock
, NULL
);
207 for(i
= 0; i
< PTINUM
; i
++)
209 if(dev_list
[i
].SessionHandle
== 0)
212 struct read_thread_param
*para
;
213 if(!cs_malloc(¶
, sizeof(struct read_thread_param
)))
216 para
->cli
= cur_client();
218 int32_t ret
= start_thread("stapi read", stapi_read_thread
, (void *)para
, &dev_list
[i
].thread
, 1, 0);
227 cs_log("liboscam_stapi v.%s initialized", oscam_stapi_LibVersion());
231 int32_t stapi_activate_section_filter(int32_t fd
, uint8_t *filter
, uint8_t *mask
)
233 int n
= 0, ret
= 852049;
234 while(n
< 3 && ret
== 852049)
236 ret
= oscam_stapi_FilterSet(fd
, filter
, mask
);
239 cs_log_dbg(D_DVBAPI
, "Error: oscam_stapi_FilterSet; %d", ret
);
247 cs_log("Error: stapi_activate_section_filter: %d", ret
);
253 int32_t stapi_set_filter(int32_t demux_id
, uint16_t pid
, uint8_t *filter
, uint8_t *mask
, int32_t num
, char *pmtfile
)
258 uint16_t pids
[1] = { pid
};
259 struct s_dvbapi_priority
*p
;
263 cs_log_dbg(D_DVBAPI
, "No valid pmtfile!");
267 cs_log_dbg(D_DVBAPI
, "pmt file %s demux_id %d", pmtfile
, demux_id
);
269 for(p
= dvbapi_priority
; p
!= NULL
; p
= p
->next
)
271 if(p
->type
!= 's') { continue; } // stapi rule?
272 if(strcmp(pmtfile
, p
->pmtfile
) != 0) { continue; } // same file?
274 for(i
= 0; i
< PTINUM
; i
++)
276 if(strcmp(dev_list
[i
].name
, p
->devname
) == 0 && p
->disablefilter
== 0) // check device name and if filtering is enabled!
278 cs_log_dbg(D_DVBAPI
, "set stapi filter on %s for pid %04X", dev_list
[i
].name
, pids
[0]);
279 ret
= stapi_do_set_filter(demux_id
, &dev_list
[i
].demux_fd
[demux_id
][num
], pids
, 1, filter
, mask
, i
);
280 if(ret
> 0) // success
282 cs_log_dbg(D_DVBAPI
, "%s filter %d set (pid %04X)", dev_list
[i
].name
, num
, pid
);
283 return ret
; // return filternumber
287 cs_log_dbg(D_DVBAPI
, "Error setting new filter for pid %04X on %s!", pid
, dev_list
[i
].name
);
288 return -1; // set return to error
296 cs_log_dbg(D_DVBAPI
, "No matching S: line in oscam.dvbapi for pmtfile %s -> stop descrambling!", pmtfile
);
297 snprintf(dest
, sizeof(dest
), "%s%s", TMPDIR
, demux
[demux_id
].pmt_file
);
298 unlink(dest
); // remove obsolete pmt file
299 dvbapi_stop_descrambling(demux_id
, 0);
304 int32_t stapi_remove_filter(int32_t demux_id
, int32_t num
, char *pmtfile
)
307 struct s_dvbapi_priority
*p
;
309 if(!pmtfile
) { return 0; }
311 for(p
= dvbapi_priority
; p
!= NULL
; p
= p
->next
)
313 if(p
->type
!= 's') { continue; }
314 if(strcmp(pmtfile
, p
->pmtfile
) != 0)
317 for(i
= 0; i
< PTINUM
; i
++)
319 if(strcmp(dev_list
[i
].name
, p
->devname
) == 0 && p
->disablefilter
== 0)
321 ret
= stapi_do_remove_filter(demux_id
, &dev_list
[i
].demux_fd
[demux_id
][num
], i
);
327 cs_log_dbg(D_DVBAPI
, "filter %d removed", num
);
331 cs_log_dbg(D_DVBAPI
, "Error: filter %d was not removed!", num
);
336 static uint32_t check_slot(int32_t dev_id
, uint32_t checkslot
, FILTERTYPE
*skipfilter
)
339 for(d
= 0; d
< MAX_DEMUX
; d
++)
341 for(f
= 0; f
< MAX_FILTER
; f
++)
343 if(skipfilter
&& &dev_list
[dev_id
].demux_fd
[d
][f
] == skipfilter
)
345 for(l
= 0; l
< dev_list
[dev_id
].demux_fd
[d
][f
].NumSlots
; l
++)
347 if(checkslot
== dev_list
[dev_id
].demux_fd
[d
][f
].SlotHandle
[l
])
349 return dev_list
[dev_id
].demux_fd
[d
][f
].BufferHandle
[l
];
358 static int32_t stapi_do_set_filter(int32_t demux_id
, FILTERTYPE
*filter
, uint16_t *pids
, int32_t pidcount
, uint8_t *filt
, uint8_t *mask
, int32_t dev_id
)
360 uint32_t FilterAssociateError
= 0;
364 filter
->BufferHandle
[0] = 0;
365 filter
->SlotHandle
[0] = 0;
367 if(dev_list
[dev_id
].SessionHandle
== 0) { return 0; }
369 uint32_t FilterAllocateError
= oscam_stapi_FilterAllocate(dev_list
[dev_id
].SessionHandle
, &filter
->fd
);
371 if(FilterAllocateError
!= 0)
373 cs_log("FilterAllocate problem");
378 for(k
= 0; k
< pidcount
; k
++)
380 uint16_t pid
= pids
[k
];
382 uint32_t QuerySlot
= oscam_stapi_PidQuery(dev_list
[dev_id
].name
, pid
);
383 int32_t SlotInit
= 1;
387 uint32_t checkslot
= check_slot(dev_id
, QuerySlot
, NULL
);
390 filter
->SlotHandle
[k
] = QuerySlot
;
391 filter
->BufferHandle
[k
] = checkslot
;
396 cs_log("overtake: clear pid: %d", oscam_stapi_SlotClearPid(QuerySlot
));
403 ret
= oscam_stapi_SlotInit(dev_list
[dev_id
].SessionHandle
, dev_list
[dev_id
].SignalHandle
, &filter
->BufferHandle
[k
], &filter
->SlotHandle
[k
], pid
);
406 FilterAssociateError
= oscam_stapi_FilterAssociate(filter
->fd
, filter
->SlotHandle
[k
]);
410 uint32_t FilterSetError
= oscam_stapi_FilterSet(filter
->fd
, filt
, mask
);
412 if(ret
|| FilterAllocateError
|| FilterAssociateError
|| FilterSetError
)
414 cs_log("set_filter: dev: %d FAl: %d FAs: %d FS: %d",
415 dev_id
, FilterAllocateError
, FilterAssociateError
, FilterSetError
);
416 stapi_do_remove_filter(demux_id
, filter
, dev_id
);
421 return filter
->fd
; // return fd of filter
425 static int32_t stapi_do_remove_filter(int32_t UNUSED(demux_id
), FILTERTYPE
*filter
, int32_t dev_id
)
427 if(filter
->fd
== 0) { return 0; }
429 uint32_t BufferDeallocateError
= 0, SlotDeallocateError
= 0;
431 if(dev_list
[dev_id
].SessionHandle
== 0) { return 0; }
434 for(k
= 0; k
< filter
->NumSlots
; k
++)
436 uint32_t checkslot
= check_slot(dev_id
, filter
->SlotHandle
[k
], filter
);
440 BufferDeallocateError
= oscam_stapi_BufferDeallocate(filter
->BufferHandle
[k
]);
441 SlotDeallocateError
= oscam_stapi_SlotDeallocate(filter
->SlotHandle
[k
]);
444 uint32_t FilterDeallocateError
= oscam_stapi_FilterDeallocate(filter
->fd
);
446 memset(filter
, 0, sizeof(FILTERTYPE
));
448 if(BufferDeallocateError
|| SlotDeallocateError
|| FilterDeallocateError
)
450 cs_log("remove_filter: dev: %d BD: %d SD: %d FDe: %d",
451 dev_id
, BufferDeallocateError
, SlotDeallocateError
, FilterDeallocateError
);
460 static void stapi_cleanup_thread(void *dev
)
462 int32_t dev_index
= (int)dev
;
465 ErrorCode
= oscam_stapi_Close(dev_list
[dev_index
].SessionHandle
);
467 cs_log("liboscam_stapi: PTI %s closed - %d\n", dev_list
[dev_index
].name
, ErrorCode
);
468 dev_list
[dev_index
].SessionHandle
= 0;
471 static void *stapi_read_thread(void *sparam
)
473 int32_t dev_index
, ErrorCode
, i
, j
, CRCValid
;
474 uint32_t QueryBufferHandle
= 0, DataSize
= 0;
475 uint8_t buf
[BUFFLEN
];
477 struct read_thread_param
*para
= sparam
;
478 dev_index
= para
->id
;
480 SAFE_SETSPECIFIC(getclient
, para
->cli
);
481 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS
, NULL
);
482 pthread_cleanup_push(stapi_cleanup_thread
, (void *) dev_index
);
484 int32_t error_count
= 0;
488 QueryBufferHandle
= 0;
489 ErrorCode
= oscam_stapi_SignalWaitBuffer(dev_list
[dev_index
].SignalHandle
, &QueryBufferHandle
, 1000);
495 case 852042: // ERROR_SIGNAL_ABORTED
496 cs_log("Caught abort signal");
499 case 11: // ERROR_TIMEOUT:
500 //cs_log("timeout %d", dev_index);
501 //TODO: if pidindex == -1 try next
505 if(QueryBufferHandle
!= 0)
507 cs_log("SignalWaitBuffer error: %d", ErrorCode
);
508 oscam_stapi_BufferFlush(QueryBufferHandle
);
511 cs_log("SignalWaitBuffer: index %d ErrorCode: %d - QueryBuffer: %x", dev_index
, ErrorCode
, QueryBufferHandle
);
515 cs_log("Too many errors in reader thread %d, quitting.", dev_index
);
522 uint32_t NumFilterMatches
= 0;
523 int32_t demux_id
= 0, filter_num
= 0;
527 uint32_t MatchedFilterList
[10];
528 ErrorCode
= oscam_stapi_BufferReadSection(QueryBufferHandle
, MatchedFilterList
, 10, &NumFilterMatches
, &CRCValid
, buf
, BUFFLEN
, &DataSize
);
532 cs_log("BufferRead: index: %d ErrorCode: %d", dev_index
, ErrorCode
);
540 SAFE_MUTEX_LOCK(&filter_lock
); // don't use cs_lock() here; multiple threads using same s_client struct
541 for(k
= 0; k
< NumFilterMatches
; k
++)
543 for(i
= 0; i
< MAX_DEMUX
; i
++)
545 for(j
= 0; j
< MAX_FILTER
; j
++)
547 if(dev_list
[dev_index
].demux_fd
[i
][j
].fd
== MatchedFilterList
[k
])
552 dvbapi_process_input(demux_id
, filter_num
, buf
, DataSize
, 0);
557 SAFE_MUTEX_UNLOCK(&filter_lock
);
560 pthread_cleanup_pop(0);
566 #define DISASSOCIATE 0
571 static void stapi_DescramblerAssociate(int32_t demux_id
, uint16_t pid
, int32_t mode
, int32_t n
)
574 int32_t ErrorCode
= 0;
576 if(dev_list
[n
].SessionHandle
== 0) { return; }
578 Slot
= oscam_stapi_PidQuery(dev_list
[n
].name
, pid
);
579 if(!Slot
) { return; }
581 if(demux
[demux_id
].DescramblerHandle
[n
] == 0) { return; }
583 if(mode
== ASSOCIATE
)
586 for(k
= 0; k
< SLOTNUM
; k
++)
588 if(demux
[demux_id
].slot_assc
[n
][k
] == Slot
)
594 ErrorCode
= oscam_stapi_DescramblerAssociate(demux
[demux_id
].DescramblerHandle
[n
], Slot
);
595 cs_log_dbg(D_DVBAPI
, "set pid %04x on %s", pid
, dev_list
[n
].name
);
598 { cs_log("DescramblerAssociate %d", ErrorCode
); }
600 for(k
= 0; k
< SLOTNUM
; k
++)
602 if(demux
[demux_id
].slot_assc
[n
][k
] == 0)
604 demux
[demux_id
].slot_assc
[n
][k
] = Slot
;
611 ErrorCode
= oscam_stapi_DescramblerDisassociate(demux
[demux_id
].DescramblerHandle
[n
], Slot
);
613 { cs_log_dbg(D_DVBAPI
, "DescramblerDisassociate %d", ErrorCode
); }
615 cs_log_dbg(D_DVBAPI
, "unset pid %04x on %s", pid
, dev_list
[n
].name
);
618 for(k
= 0; k
< SLOTNUM
; k
++)
620 if(demux
[demux_id
].slot_assc
[n
][k
] == Slot
)
622 demux
[demux_id
].slot_assc
[n
][k
] = 0;
631 static void stapi_startdescrambler(int32_t demux_id
, int32_t dev_index
, int32_t mode
)
635 if(mode
== DE_START
&& demux
[demux_id
].DescramblerHandle
[dev_index
] == 0)
637 uint32_t DescramblerHandle
= 0;
638 ErrorCode
= oscam_stapi_DescramblerAllocate(dev_list
[dev_index
].SessionHandle
, &DescramblerHandle
);
641 cs_log("DescramblerAllocate: ErrorCode: %d SignalHandle: %x", ErrorCode
, dev_list
[dev_index
].SignalHandle
);
645 demux
[demux_id
].DescramblerHandle
[dev_index
] = DescramblerHandle
;
648 if(mode
== DE_STOP
&& demux
[demux_id
].DescramblerHandle
[dev_index
] > 0)
650 ErrorCode
= oscam_stapi_DescramblerDeallocate(demux
[demux_id
].DescramblerHandle
[dev_index
]);
653 { cs_log("DescramblerDeallocate: ErrorCode: %d", ErrorCode
); }
655 demux
[demux_id
].DescramblerHandle
[dev_index
] = 0;
661 int32_t stapi_set_pid(int32_t demux_id
, int32_t UNUSED(num
), uint32_t idx
, uint16_t UNUSED(pid
), char *UNUSED(pmtfile
))
665 if(idx
== INDEX_INVALID
)
667 for(n
= 0; n
< PTINUM
; n
++)
669 if(demux
[demux_id
].DescramblerHandle
[n
] == 0) { continue; }
671 cs_log_dbg(D_DVBAPI
, "stop descrambling PTI: %s", dev_list
[n
].name
);
672 stapi_startdescrambler(demux_id
, n
, DE_STOP
);
673 memset(demux
[demux_id
].slot_assc
[n
], 0, sizeof(demux
[demux_id
].slot_assc
[n
]));
680 int32_t stapi_write_cw(int32_t demux_id
, uint8_t *cw
, uint16_t *STREAMpids
, int32_t STREAMpidcount
, char *pmtfile
)
682 int32_t ErrorCode
, l
, n
, k
;
684 memset(nullcw
, 0, 8);
685 char *text
[] = { "even", "odd" };
687 if(!pmtfile
) { return 0; }
689 for(n
= 0; n
< PTINUM
; n
++)
691 if(dev_list
[n
].SessionHandle
== 0) { continue; }
692 if(demux
[demux_id
].DescramblerHandle
[n
] == 0)
694 struct s_dvbapi_priority
*p
;
696 for(p
= dvbapi_priority
; p
!= NULL
; p
= p
->next
)
698 if(p
->type
!= 's') { continue; }
699 if(strcmp(pmtfile
, p
->pmtfile
) != 0)
702 if(strcmp(dev_list
[n
].name
, p
->devname
) == 0)
704 cs_log_dbg(D_DVBAPI
, "start descrambling PTI: %s", dev_list
[n
].name
);
705 stapi_startdescrambler(demux_id
, n
, DE_START
);
710 if(demux
[demux_id
].DescramblerHandle
[n
] == 0) { continue; }
712 for(k
= 0; k
< STREAMpidcount
; k
++)
714 stapi_DescramblerAssociate(demux_id
, STREAMpids
[k
], ASSOCIATE
, n
);
718 int32_t pidnum
= demux
[demux_id
].pidindex
; // get current pidindex used for descrambling
719 uint32_t idx
= demux
[demux_id
].ECMpids
[pidnum
].index
[0];
721 if(idx
== INDEX_INVALID
) // if no indexer for this pid get one!
723 idx
= dvbapi_get_desc_index(demux_id
, pidnum
, 0);
724 cs_log_dbg(D_DVBAPI
, "Demuxer %d PID: %d CAID: %04X ECMPID: %04X is using index %d", demux_id
, pidnum
,
725 demux
[demux_id
].ECMpids
[pidnum
].CAID
, demux
[demux_id
].ECMpids
[pidnum
].ECM_PID
, idx
);
728 for(l
= 0; l
< 2; l
++)
730 // Skip check for BISS1 - cw could be indeed zero
731 // Skip check for BISS2 - we use the extended cw, so the "simple" cw is always zero
732 if(memcmp(cw
+ (l
* 8), demux
[demux_id
].last_cw
[0][l
], 8) != 0
733 && (memcmp(cw
+ (l
* 8), nullcw
, 8) != 0 || caid_is_biss(demux
[demux_id
].ECMpids
[pidnum
].CAID
)))
735 for(n
= 0; n
< PTINUM
; n
++)
737 if(demux
[demux_id
].DescramblerHandle
[n
] == 0) { continue; }
739 ErrorCode
= oscam_stapi_DescramblerSet(demux
[demux_id
].DescramblerHandle
[n
], l
, cw
+ (l
* 8));
741 { cs_log("DescramblerSet: ErrorCode: %d", ErrorCode
); }
743 memcpy(demux
[demux_id
].last_cw
[0][l
], cw
+ (l
* 8), 8);
744 cs_log_dbg(D_DVBAPI
, "write cw %s index: %d %s", text
[l
], demux_id
, dev_list
[n
].name
);
752 // Needed for compatability with liboscam_stapi.a
754 void cs_log(const char *fmt
, ...)
759 va_start(params
, fmt
);
760 vsnprintf(log_txt
, sizeof(log_txt
), fmt
, params
);
763 cs_log_txt(MODULE_LOG_PREFIX
, "%s", log_txt
);