CI/CA Patch - please test

Denis Lackovic delacko at gmail.com
Wed Feb 18 16:04:33 CET 2009


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


More information about the Getstream mailing list