CI/CA Patch - please test
Denis Lackovic
delacko at gmail.com
Wed Feb 18 17:29:07 CET 2009
I poked arround the code and found out I could get getstream to work
by replacing a few lines in ca.c:
I replaced
-----
g_thread_init (NULL);
-----
with
-----
if (!g_threads_got_initialized)
g_thread_init (NULL);
-----
I will test in the next few days to see if it is working.
On Wed, Feb 18, 2009 at 4:04 PM, Denis Lackovic <delacko at gmail.com> wrote:
> Hi,
>
> I just got a CAM module and tried to use it with getstream, but when
> trying to start it up, getstream crashes if using a card which has a
> CI module attached.
> Cards without a CI module attached work fine.
> I use S2API drivers , getstream with your patch, and card is
> Technotrend S2-3200 + CI.
>
>
>
> --------------------
> > getstream -d -c astra_sat.conf
> 2009-02-18 15:53:48.747 Initialize common interface...
>
> GThread-ERROR **: GThread system may only be initialized once.
> aborting...
> --------------------
>
>
> Kernel messagey, for each startup of getstream:
> --------------------
> [229619.035165] dvb_ca adapter 2: DVB CAM detected and initialised successfully
> --------------------
>
>
>
>
>
> 2009/2/13 Florian Lohoff <flo at rfc822.org>:
>> On Thu, Feb 12, 2009 at 06:25:06PM +0600, gameover wrote:
>>> Only this messages give getstream program with this patch
>>>
>>> "
>>> Initialize common interface...
>>>
>>>
>>> GLib-ERROR **: The thread system is not yet initialized.
>>> "
>>> ,
>>> I have s2-3200 with CI , CAM Irdeto 2 with S2API drivers
>>
>> Can you try this?
>>
>> Its basically the same patch rebased to current getstreams head and with
>> g_thread_init added:
>>
>>
>> From e7691ecf680caa39ff2905529409e6b3b4981359 Mon Sep 17 00:00:00 2001
>> From: Florian Lohoff <flo at rfc822.org>
>> Date: Thu, 12 Feb 2009 10:09:42 +0100
>> Subject: [PATCH] CA Support added
>>
>> ---
>> Makefile | 6 +-
>> ca.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>> ca.h | 91 +++++++++++++++
>> getstream.c | 8 +-
>> getstream.h | 4 +
>> pmt.c | 14 ++-
>> 6 files changed, 488 insertions(+), 6 deletions(-)
>> create mode 100644 ca.c
>> create mode 100644 ca.h
>>
>> diff --git a/Makefile b/Makefile
>> index 345a635..6810bf8 100644
>> --- a/Makefile
>> +++ b/Makefile
>> @@ -1,7 +1,7 @@
>> CC=gcc
>> -CFLAGS=-O0 -g -Wall -I. -I/usr/include/glib-2.0/ -I/usr/lib/glib-2.0/include/
>> -LDFLAGS=-levent -lglib-2.0 -lpthread
>> -OBJ-getstream=getstream.o fe.o crc32.o \
>> +CFLAGS=-O0 -g -Wall -I. -I/usr/include/glib-2.0/ -I/usr/lib/glib-2.0/include/ -D_GNU_SOURCE
>> +LDFLAGS=-levent -lglib-2.0 -lgthread-2.0 -lpthread -ldvben50221 -ldvbapi -lucsi
>> +OBJ-getstream=getstream.o ca.o fe.o crc32.o \
>> libhttp.o libconf.o config.o util.o logging.o \
>> stream.o input.o \
>> output.o output_http.o output_udp.o output_pipe.o output_rtp.o \
>> diff --git a/ca.c b/ca.c
>> new file mode 100644
>> index 0000000..38c7a9b
>> --- /dev/null
>> +++ b/ca.c
>> @@ -0,0 +1,371 @@
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <unistd.h>
>> +#include <poll.h>
>> +#include <errno.h>
>> +
>> +#include <libdvben50221/en50221_stdcam.h>
>> +
>> +#include <libucsi/section.h>
>> +#include <libucsi/mpeg/section.h>
>> +#include <libucsi/dvb/section.h>
>> +
>> +#include <libdvbapi/dvbdemux.h>
>> +#include <libdvbapi/dvbca.h>
>> +
>> +#include <pthread.h>
>> +#include <sys/types.h>
>> +
>> +#include <sys/syscall.h>
>> +#include <sched.h>
>> +
>> +#include <glib.h>
>> +
>> +#include "getstream.h"
>> +#include "ca.h"
>> +
>> +static void *ca_monitor(void *arg);
>> +
>> +/* TODO: old fashioned callbacks, need some work */
>> +void send_mmi_menu_answ(void *value) {
>> + /*
>> + int val = (int)value;
>> + intca_t *this = (intca_t*)ui.mmimenu->ca;
>> + en50221_app_mmi_menu_answ(this->stdcam->mmi_resource,
>> + ui.mmimenu->session_number,
>> + val);
>> + */
>> + /* FIXME: IMPLEMENT ME! */
>> +
>> +}
>> +
>> +void send_mmi_answ(uint8_t * value, int length) {
>> + /*
>> + intca_t *this = (intca_t*)ui.pin_query->ca;
>> + en50221_app_mmi_answ(this->stdcam->mmi_resource,
>> + this->stdcam->mmi_session_number,
>> + MMI_ANSW_ID_ANSWER, value,
>> + length);
>> + */
>> +
>> + /* FIXME: IMPELEMENT ME! */
>> +}
>> +
>> +void open_mmi_menu(void *ca) {
>> + struct intca_s *intca=ca;
>> + int ret;
>> +
>> + ret=en50221_app_ai_entermenu(intca->stdcam->ai_resource,
>> + intca->stdcam->ai_session_number);
>> +
>> + logwrite(LOG_INFO, "Enter CI-Menu! %d, %d, %d", ret,
>> + intca->stdcam->ai_session_number,
>> + intca->stdcam->mmi_session_number);
>> +}
>> +
>> +/* ends here */
>> +
>> +static int ai_callback(void *arg, uint8_t slot_id, uint16_t session_number,
>> + uint8_t application_type,
>> + uint16_t application_manufacturer,
>> + uint16_t manufacturer_code, uint8_t menu_string_length,
>> + uint8_t * menu_string) {
>> +
>> + logwrite(LOG_INFO, "CAM %d Application type: %02x", slot_id,
>> + application_type);
>> + logwrite(LOG_INFO, "CAM %d Application manufacturer: %04x", slot_id,
>> + application_manufacturer);
>> + logwrite(LOG_INFO, "CAM %d Manufacturer code: %04x", slot_id,
>> + manufacturer_code);
>> + logwrite(LOG_INFO, "CAM %d Menu string: %.*s", slot_id,
>> + menu_string_length, menu_string);
>> +
>> + return 0;
>> +}
>> +
>> +static int ca_info_callback(void *arg, uint8_t slot_id,
>> + uint16_t session_number, uint32_t ca_id_count,
>> + uint16_t *ca_ids) {
>> +
>> + struct intca_s *intca=arg;
>> + int i;
>> +
>> + logwrite(LOG_INFO, "CAM %d supports the following ca system ids:",
>> + slot_id);
>> +
>> + for(i=0;i<ca_id_count;i++)
>> + logwrite(LOG_INFO, " 0x%04x\n", ca_ids[i]);
>> +
>> + intca->ca_resource_connected = 1;
>> + return 0;
>> +}
>> +
>> +static int mmi_close_callback(void *arg, uint8_t slot_id,
>> + uint16_t session_number, uint8_t cmd_id,
>> + uint8_t delay) {
>> +
>> + /*
>> + * FIXME close some menu
>> + * note: not entirely correct as its supposed to delay if asked
>> + */
>> + return 0;
>> +}
>> +
>> +static int mmi_display_control_callback(void *arg, uint8_t slot_id,
>> + uint16_t session_number,
>> + uint8_t cmd_id, uint8_t mmi_mode) {
>> +
>> + struct en50221_app_mmi_display_reply_details reply;
>> + struct intca_s *intca=arg;
>> +
>> + /* don't support any commands but set mode */
>> +
>> + if(cmd_id != MMI_DISPLAY_CONTROL_CMD_ID_SET_MMI_MODE) {
>> +
>> + en50221_app_mmi_display_reply(intca->stdcam->mmi_resource,
>> + session_number,
>> + MMI_DISPLAY_REPLY_ID_UNKNOWN_CMD_ID,
>> + &reply);
>> +
>> + return 0;
>> + }
>> +
>> + /* we only support high level mode */
>> + if(mmi_mode != MMI_MODE_HIGH_LEVEL) {
>> +
>> + en50221_app_mmi_display_reply(intca->stdcam->mmi_resource,
>> + session_number,
>> + MMI_DISPLAY_REPLY_ID_UNKNOWN_MMI_MODE,
>> + &reply);
>> +
>> + return 0;
>> + }
>> +
>> + /* ack the high level open */
>> + reply.u.mode_ack.mmi_mode=mmi_mode;
>> + en50221_app_mmi_display_reply(intca->stdcam->mmi_resource,
>> + session_number,
>> + MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK,
>> + &reply);
>> +
>> + return 0;
>> +}
>> +
>> +static int mmi_enq_callback(void *arg, uint8_t slot_id,
>> + uint16_t session_number, uint8_t blind_answer,
>> + uint8_t expected_answer_length, uint8_t * text,
>> + uint32_t text_size) {
>> + struct intca_s *intca=arg;
>> +
>> + en50221_app_mmi_answ(intca->stdcam->mmi_resource,
>> + intca->stdcam->mmi_session_number,
>> + MMI_ANSW_ID_CANCEL, NULL, 0);
>> +
>> + /*
>> + * FIXME handle the enquiry somehow
>> + * probably best solution would be calling a user-configurable
>> + * script, so that pins can be handled
>> + */
>> +
>> + return 0;
>> +}
>> +
>> +
>> +static int mmi_menu_callback(void *arg, uint8_t slot_id,
>> + uint16_t session_number,
>> + struct en50221_app_mmi_text *title,
>> + struct en50221_app_mmi_text *sub_title,
>> + struct en50221_app_mmi_text *bottom,
>> + uint32_t item_count,
>> + struct en50221_app_mmi_text *items,
>> + uint32_t item_raw_length, uint8_t * items_raw) {
>> +
>> + struct intca_s *intca=arg;
>> +
>> + logwrite(LOG_INFO, "MMI menu callback %d", session_number);
>> +
>> + /* FIXME handle the menu - for now just answer with 0x01 */
>> + if(1) {
>> + en50221_app_mmi_menu_answ(intca->stdcam->mmi_resource,
>> + intca->stdcam->mmi_session_number,
>> + 0x01);
>> +
>> + return 0;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static void *ca_monitor(void *arg) {
>> + struct intca_s *intca=arg;
>> +
>> + while(!intca->stop_thread)
>> + intca->stdcam->poll(intca->stdcam);
>> +
>> + return (void *) 0;
>> +}
>> +
>> +static void ca_pmt_push_cam(struct intca_s *intca, struct psisec_s *psisec) {
>> + struct section *section;
>> + struct section_ext *section_ext;
>> + struct mpeg_pmt_section *pmt;
>> + int size;
>> + uint8_t capmt[4096];
>> +
>> + section=section_codec(psisec->data, psisec->len);
>> + if (!section)
>> + return;
>> +
>> + section_ext=section_ext_decode(section, 0);
>> + if (!section_ext)
>> + return;
>> +
>> + pmt=mpeg_pmt_section_codec(section_ext);
>> + if (!pmt)
>> + return;
>> +
>> + if(!intca->ca_resource_connected)
>> + return;
>> +
>> + logwrite(LOG_INFO, "Received new PMT, send it to CAM");
>> +
>> +
>> + size=en50221_ca_format_pmt(pmt, capmt, sizeof(capmt),
>> + intca->moveca, CA_LIST_MANAGEMENT_ADD,
>> + CA_PMT_CMD_ID_OK_DESCRAMBLING);
>> +
>> + if (size<0) {
>> + logwrite(LOG_ERROR, "en50221_ca_format_pmt returned size %d", size);
>> + return;
>> + }
>> +
>> + if(en50221_app_ca_pmt(intca->stdcam->ca_resource,
>> + intca->stdcam->ca_session_number,
>> + capmt, size)) {
>> +
>> + logwrite(LOG_ERROR, "Failed to send PMT");
>> + return;
>> + }
>> +
>> + return;
>> +}
>> +
>> +/*
>> + * This threads waits for the PAT/PMT forwarding to pass in a PMT section
>> + * via the async queue. g_async_queue_pop will put the thread to sleep until
>> + * there is one.
>> + *
>> + */
>> +static void *ca_pmt_monitor(void *arg) {
>> + struct intca_s *intca=arg;
>> + struct psisec_s *section;
>> +
>> + g_thread_init(NULL);
>> + g_async_queue_ref(intca->pmtqueue);
>> +
>> + while(42) {
>> + section=g_async_queue_pop(intca->pmtqueue);
>> + ca_pmt_push_cam(intca, section);
>> + g_free(section);
>> + }
>> +}
>> +
>> +void ca_pmt_section_push(struct intca_s *intca, struct psisec_s *section) {
>> + struct psisec_s *sectionclone;
>> +
>> + /* malloc + copy in the hot path? */
>> + sectionclone=g_memdup(section, sizeof(struct psisec_s));
>> +
>> + /* Push it into the threads pmt queue */
>> + g_async_queue_push(intca->pmtqueue, sectionclone);
>> +
>> + return;
>> +}
>> +
>> +struct intca_s *new_ca(int adapter, int demuxer, int caslot, int moveca,
>> + GList *streams) {
>> + struct intca_s *intca;
>> +
>> + logwrite(LOG_INFO, "Initialize common interface...");
>> +
>> + intca=malloc(sizeof(struct intca_s));
>> +
>> + intca->pmtqueue=g_async_queue_new();
>> +
>> + intca->ca_resource_connected = 0;
>> +
>> + intca->stop_thread = 0;
>> +
>> + intca->adapter = adapter;
>> + intca->demuxer = demuxer;
>> + intca->caslot = caslot;
>> + intca->moveca = moveca;
>> +
>> + intca->inputs = 0;
>> +
>> + /* create transportlayer */
>> + intca->tl = en50221_tl_create(1, 16);
>> + if(intca->tl == NULL) {
>> + logwrite(LOG_ERROR, "Failed to create transport layer");
>> + return NULL;
>> + }
>> +
>> + /* create session layer */
>> + intca->sl = en50221_sl_create(intca->tl, 16);
>> + if(intca->sl == NULL) {
>> + logwrite(LOG_ERROR, "Failed to create session layer");
>> + en50221_tl_destroy(intca->tl);
>> + return NULL;
>> + }
>> +
>> + /* create stdcam interface */
>> + intca->stdcam = en50221_stdcam_create(intca->adapter, intca->caslot,
>> + intca->tl, intca->sl);
>> +
>> + if(intca->stdcam == NULL) {
>> + en50221_sl_destroy(intca->sl);
>> + en50221_tl_destroy(intca->tl);
>> + logwrite(LOG_ERROR, "Failed to create stdcam");
>> + return NULL;
>> + }
>> +
>> + /* hook up the AI callbacks */
>> + if(intca->stdcam->ai_resource) {
>> + en50221_app_ai_register_callback(intca->stdcam->ai_resource,
>> + ai_callback, intca);
>> + }
>> +
>> + /* hook up the CA callbacks */
>> + if(intca->stdcam->ca_resource) {
>> + en50221_app_ca_register_info_callback(intca->stdcam->ca_resource,
>> + ca_info_callback, intca);
>> + }
>> +
>> + /* hook up the MMI callbacks */
>> + if(intca->stdcam->mmi_resource) {
>> + en50221_app_mmi_register_close_callback(intca->
>> + stdcam->mmi_resource,
>> + mmi_close_callback,
>> + intca);
>> +
>> + en50221_app_mmi_register_display_control_callback(intca->stdcam->mmi_resource,
>> + mmi_display_control_callback,
>> + intca);
>> +
>> + en50221_app_mmi_register_enq_callback(intca->stdcam->mmi_resource,
>> + mmi_enq_callback, intca);
>> +
>> + en50221_app_mmi_register_menu_callback(intca->stdcam->mmi_resource,
>> + mmi_menu_callback, intca);
>> +
>> + en50221_app_mmi_register_list_callback(intca->stdcam->mmi_resource,
>> + mmi_menu_callback, intca);
>> + }
>> +
>> + pthread_create(&intca->cathread, NULL, ca_monitor, intca);
>> + pthread_create(&intca->pmtthread, NULL, ca_pmt_monitor, intca);
>> +
>> + intca->state = ca_running;
>> +
>> + return intca;
>> +}
>> diff --git a/ca.h b/ca.h
>> new file mode 100644
>> index 0000000..ce35e5b
>> --- /dev/null
>> +++ b/ca.h
>> @@ -0,0 +1,91 @@
>> +/* ca interface header */
>> +
>> +#ifndef CA_H_
>> +
>> +#define CA_H_
>> +
>> +#include <stdint.h>
>> +#include <glib.h>
>> +#include <sys/poll.h>
>> +
>> +#include "psi.h"
>> +
>> +#define MAX_PROGRAMS 50
>> +
>> +enum ca_state {
>> + ca_stopped = 0x00,
>> + ca_running = 0x01,
>> + ca_paused = 0x02
>> +};
>> +
>> +struct program {
>> + int pnr;
>> + int pmt_version;
>> +};
>> +
>> +struct intca_s {
>> + GAsyncQueue *pmtqueue;
>> +
>> + struct en50221_stdcam *stdcam;
>> + struct en50221_transport_layer *tl;
>> + struct en50221_session_layer *sl;
>> +
>> + int adapter;
>> + int demuxer;
>> + int caslot;
>> + int moveca;
>> +
>> + int pat_version;
>> + int pmt_version;
>> +
>> + int inputs;
>> +
>> + int ca_resource_connected;
>> +
>> + GList *streams;
>> +
>> + enum ca_state state;
>> +
>> + int stop_thread;
>> + pthread_t cathread;
>> + pthread_t pmtthread;
>> +};
>> +
>> +/**
>> + * constructor for the CI module
>> + * @param adapter adapter number
>> + * @param demuxer demuxer number
>> + * @param caslot caslot number
>> + * @param moveca use ca movement
>> + * @param streams list of streams to control
>> + * @return newly created ca objected
>> + */
>> +struct intca_s *new_ca(int adapter, int demuxer, int caslot, int moveca,
>> + GList * streams);
>> +
>> +
>> +/**
>> + * Sends a mmi answer to the mmi menu currently linked
>> + * to ui.mmimenu
>> + * @param value the answer value
>> + */
>> +void send_mmi_menu_answ(void *value);
>> +
>> +/**
>> + * opens a mmi menu in the ui.mmimenu
>> + * @param this_gen ca object to use
>> + */
>> +void open_mmi_menu(void *ca);
>> +
>> +
>> +/**
>> + * Send a mmi app answer to mmi session in ui.pin_query
>> + * @param value the answer value
>> + * @param length length of value
>> + */
>> +void send_mmi_answ(uint8_t * value, int length);
>> +
>> +void ca_pmt_section_push(struct intca_s *intca, struct psisec_s *section);
>> +
>> +
>> +#endif
>> diff --git a/getstream.c b/getstream.c
>> index ce834f7..8e105de 100644
>> --- a/getstream.c
>> +++ b/getstream.c
>> @@ -1,4 +1,3 @@
>> -
>> #include <sys/poll.h>
>> #include <sys/types.h>
>> #include <sys/stat.h>
>> @@ -13,6 +12,9 @@
>> #include <pthread.h>
>> #include <signal.h>
>>
>> +#include <sys/syscall.h>
>> +#include <sched.h>
>> +
>> #include <stdint.h>
>> #include <string.h>
>> #include <stdio.h>
>> @@ -132,6 +134,7 @@ int main(int argc, char **argv) {
>> if (!config)
>> exit(-1);
>>
>> + g_thread_init(NULL);
>> /* Initialize libevent */
>> event_init();
>>
>> @@ -152,6 +155,9 @@ int main(int argc, char **argv) {
>> struct adapter_s *a=al->data;
>> GList *sl=g_list_first(a->streams);
>>
>> + /* Start CI-Interface */
>> + a->ca = new_ca(a->no, 0, 0, 1, a->streams);
>> +
>> /* Tune to the one and only transponder */
>> fe_tune_init(a);
>>
>> diff --git a/getstream.h b/getstream.h
>> index 5aec52c..e461af6 100644
>> --- a/getstream.h
>> +++ b/getstream.h
>> @@ -14,6 +14,7 @@
>>
>> #include "sap.h"
>> #include "psi.h"
>> +#include "ca.h"
>>
>> #if (DVB_API_VERSION==3) && (DVB_API_VERSION_MINOR>=3)
>>
>> @@ -250,6 +251,9 @@ struct adapter_s {
>> int budgetmode;
>> GList *streams;
>>
>> + /* CI */
>> + struct intca_s *ca;
>> +
>> /* fe.c */
>> struct {
>> int fd;
>> diff --git a/pmt.c b/pmt.c
>> index 1542847..8e8c411 100644
>> --- a/pmt.c
>> +++ b/pmt.c
>> @@ -6,6 +6,7 @@
>> #include "getstream.h"
>> #include "psi.h"
>> #include "crc32.h"
>> +#include "ca.h"
>>
>> struct programcb_s {
>> void (*callback)(void *data, void *arg);
>> @@ -338,8 +339,6 @@ static void pmt_dvr_pmt_cb(void *data, void *arg) {
>> logwrite(LOG_XTREME, "pmt: dvr section callback");
>> dump_hex(LOG_XTREME, "pmt: PMT ", section->data, section->valid);
>>
>> - if (!psi_currentnext(section))
>> - return;
>>
>> if (psi_tableid(section) != PMT_TABLE_ID) {
>> logwrite(LOG_INFO, "pmt: received PMT with broken table id on pid %d", prog->pmtpid);
>> @@ -352,9 +351,20 @@ static void pmt_dvr_pmt_cb(void *data, void *arg) {
>> return;
>> }
>>
>> + if (!psi_currentnext(section))
>> + return;
>> +
>> + /*
>> + * Did something change in the PMT tables? e.g. did we get
>> + * an updated section (version number changed) or a section
>> + * which we didnt have before
>> + */
>> if (!psi_update_table(&prog->psi, section))
>> return;
>>
>> + if (prog->adapter->ca)
>> + ca_pmt_section_push(prog->adapter->ca, section);
>> +
>> pmt=pmt_parse(prog);
>>
>> if (prog->pmtlast)
>> --
>> 1.5.6.5
>>
>> Flo
>> --
>> Florian Lohoff flo at rfc822.org +49-171-2280134
>> Those who would give up a little freedom to get a little
>> security shall soon have neither - Benjamin Franklin
>>
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v1.4.6 (GNU/Linux)
>>
>> iD8DBQFJlXxoUaz2rXW+gJcRArm0AJ9Vjf/vK9LT3spEuUQ+Bxuc6RFuaQCcClnl
>> O74kz+W3I01dXjnQIBfrXvg=
>> =v6QU
>> -----END PGP SIGNATURE-----
>>
>> _______________________________________________
>> Getstream mailing list
>> Getstream at gt.owl.de
>> http://gt.owl.de/mailman/listinfo/getstream
>>
>>
>
>
>
> --
> Denis Lackovic
>
--
Denis Lackovic
More information about the Getstream
mailing list