Hi, probably someone is able to test this - i refactored a CI patch i got to use more internal infrastructure and be more like my preferred coding style. Its against current gits head and needs some libs from the libdvb family - In Debian its installing dvb-utils: diff --git a/Makefile b/Makefile index 345a635..1a6a6f6 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 -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..ebbff8b --- /dev/null +++ b/ca.c @@ -0,0 +1,370 @@ +#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_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..b7d600d 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> @@ -152,6 +154,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 a9139c6..ceca8f0 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) @@ -239,6 +240,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 fa0dabd..064b741 100644 --- a/pmt.c +++ b/pmt.c @@ -5,6 +5,7 @@ #include "getstream.h" #include "psi.h" +#include "ca.h" struct programcb_s { void (*callback)(void *data, void *arg); @@ -337,8 +338,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); @@ -351,9 +350,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) -- Florian Lohoff flo@rfc822.org +49-171-2280134 Those who would give up a little freedom to get a little security shall soon have neither - Benjamin Franklin
Hi, its mostly 2 months later and nobody objected or gave feedback to the code... I am wondering if anyone is still keen on using CI/CAM stuff? On Fri, Dec 19, 2008 at 10:17:08AM +0100, Florian Lohoff wrote:
Hi, probably someone is able to test this - i refactored a CI patch i got to use more internal infrastructure and be more like my preferred coding style. Its against current gits head and needs some libs from the libdvb family - In Debian its installing dvb-utils:
diff --git a/Makefile b/Makefile index 345a635..1a6a6f6 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 -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..ebbff8b --- /dev/null +++ b/ca.c @@ -0,0 +1,370 @@ +#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_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..b7d600d 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> @@ -152,6 +154,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 a9139c6..ceca8f0 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)
@@ -239,6 +240,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 fa0dabd..064b741 100644 --- a/pmt.c +++ b/pmt.c @@ -5,6 +5,7 @@
#include "getstream.h" #include "psi.h" +#include "ca.h"
struct programcb_s { void (*callback)(void *data, void *arg); @@ -337,8 +338,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); @@ -351,9 +350,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)
-- Florian Lohoff flo@rfc822.org +49-171-2280134 Those who would give up a little freedom to get a little security shall soon have neither - Benjamin Franklin
participants (1)
-
Florian Lohoff