Commit d6c80f22 authored by Christophe Massiot's avatar Christophe Massiot

* modules/access/dvb: Partial EN 50 221 implementation. This activates

   native support for CAM modules (without using an external program).
   When used in conjunction with --programs, it also allows to descramble
   several services with one professional CAM.
parent b2147ab9
SOURCES_dvb = \ SOURCES_dvb = \
access.c \ access.c \
linux_dvb.c \ linux_dvb.c \
en50221.c \
dvb.h \ dvb.h \
$(NULL) $(NULL)
...@@ -58,9 +58,6 @@ static void Close( vlc_object_t *p_this ); ...@@ -58,9 +58,6 @@ static void Close( vlc_object_t *p_this );
#define DEVICE_TEXT N_("Device number to use on adapter") #define DEVICE_TEXT N_("Device number to use on adapter")
#define DEVICE_LONGTEXT "" #define DEVICE_LONGTEXT ""
#define CAM_TEXT N_("Use CAM")
#define CAM_LONGTEXT ""
#define FREQ_TEXT N_("Transponder/multiplex frequency") #define FREQ_TEXT N_("Transponder/multiplex frequency")
#define FREQ_LONGTEXT N_("In kHz for DVB-S or Hz for DVB-C/T") #define FREQ_LONGTEXT N_("In kHz for DVB-S or Hz for DVB-C/T")
...@@ -131,7 +128,6 @@ vlc_module_begin(); ...@@ -131,7 +128,6 @@ vlc_module_begin();
VLC_FALSE ); VLC_FALSE );
add_integer( "dvb-device", 0, NULL, DEVICE_TEXT, DEVICE_LONGTEXT, add_integer( "dvb-device", 0, NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
VLC_TRUE ); VLC_TRUE );
add_bool( "dvb-cam", 0, NULL, CAM_TEXT, CAM_LONGTEXT, VLC_FALSE );
add_integer( "dvb-frequency", 11954000, NULL, FREQ_TEXT, FREQ_LONGTEXT, add_integer( "dvb-frequency", 11954000, NULL, FREQ_TEXT, FREQ_LONGTEXT,
VLC_FALSE ); VLC_FALSE );
add_integer( "dvb-inversion", 2, NULL, INVERSION_TEXT, INVERSION_LONGTEXT, add_integer( "dvb-inversion", 2, NULL, INVERSION_TEXT, INVERSION_LONGTEXT,
...@@ -190,7 +186,7 @@ vlc_module_end(); ...@@ -190,7 +186,7 @@ vlc_module_end();
static block_t *Block( access_t * ); static block_t *Block( access_t * );
static int Control( access_t *, int, va_list ); static int Control( access_t *, int, va_list );
#define SATELLITE_READ_ONCE 3 #define DVB_READ_ONCE 3
#define TS_PACKET_SIZE 188 #define TS_PACKET_SIZE 188
static void FilterUnset( access_t *, int i_max ); static void FilterUnset( access_t *, int i_max );
...@@ -274,13 +270,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -274,13 +270,7 @@ static int Open( vlc_object_t *p_this )
FilterSet( p_access, 0x0, OTHER_TYPE ); FilterSet( p_access, 0x0, OTHER_TYPE );
} }
p_sys->b_cam = var_GetBool( p_access, "dvb-cam" ); E_(CAMOpen)( p_access );
if ( p_sys->b_cam )
{
msg_Dbg( p_access, "initing CAM..." );
if ( E_(CAMOpen)( p_access ) < 0 )
p_sys->b_cam = VLC_FALSE;
}
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -297,9 +287,7 @@ static void Close( vlc_object_t *p_this ) ...@@ -297,9 +287,7 @@ static void Close( vlc_object_t *p_this )
E_(DVRClose)( p_access ); E_(DVRClose)( p_access );
E_(FrontendClose)( p_access ); E_(FrontendClose)( p_access );
E_(CAMClose)( p_access );
if ( p_sys->b_cam )
E_(CAMClose)( p_access );
free( p_sys ); free( p_sys );
} }
...@@ -310,40 +298,52 @@ static void Close( vlc_object_t *p_this ) ...@@ -310,40 +298,52 @@ static void Close( vlc_object_t *p_this )
static block_t *Block( access_t *p_access ) static block_t *Block( access_t *p_access )
{ {
access_sys_t *p_sys = p_access->p_sys; access_sys_t *p_sys = p_access->p_sys;
struct timeval timeout;
fd_set fds;
int i_ret;
block_t *p_block; block_t *p_block;
/* Initialize file descriptor set */ for ( ; ; )
FD_ZERO( &fds );
FD_SET( p_sys->i_handle, &fds );
/* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
/* Find if some data is available */
while( (i_ret = select( p_sys->i_handle + 1, &fds, NULL, NULL, &timeout )) == 0 ||
(i_ret < 0 && errno == EINTR) )
{ {
struct timeval timeout;
fd_set fds;
int i_ret;
/* Initialize file descriptor set */
FD_ZERO( &fds ); FD_ZERO( &fds );
FD_SET( p_sys->i_handle, &fds ); FD_SET( p_sys->i_handle, &fds );
/* We'll wait 0.5 second if nothing happens */
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 500000; timeout.tv_usec = 500000;
if( p_access->b_die ) /* Find if some data is available */
i_ret = select( p_sys->i_handle + 1, &fds, NULL, NULL, &timeout );
if ( p_access->b_die )
return NULL; return NULL;
}
if ( i_ret < 0 ) if ( i_ret < 0 && errno == EINTR )
{ continue;
msg_Err( p_access, "select error (%s)", strerror(errno) );
return NULL; if ( i_ret < 0 )
{
msg_Err( p_access, "select error (%s)", strerror(errno) );
return NULL;
}
if ( p_sys->i_ca_handle && mdate() > p_sys->i_ca_next_event )
{
E_(CAMPoll)( p_access );
p_sys->i_ca_next_event = mdate() + p_sys->i_ca_timeout;
}
if ( FD_ISSET( p_sys->i_handle, &fds ) )
{
break;
}
} }
p_block = block_New( p_access, SATELLITE_READ_ONCE * TS_PACKET_SIZE ); p_block = block_New( p_access, DVB_READ_ONCE * TS_PACKET_SIZE );
if( ( p_block->i_buffer = read( p_sys->i_handle, p_block->p_buffer, SATELLITE_READ_ONCE * TS_PACKET_SIZE ) ) <= 0 ) if( ( p_block->i_buffer = read( p_sys->i_handle, p_block->p_buffer,
DVB_READ_ONCE * TS_PACKET_SIZE ) ) <= 0 )
{ {
msg_Err( p_access, "read failed (%s)", strerror(errno) ); msg_Err( p_access, "read failed (%s)", strerror(errno) );
block_Release( p_block ); block_Release( p_block );
...@@ -376,7 +376,7 @@ static int Control( access_t *p_access, int i_query, va_list args ) ...@@ -376,7 +376,7 @@ static int Control( access_t *p_access, int i_query, va_list args )
/* */ /* */
case ACCESS_GET_MTU: case ACCESS_GET_MTU:
pi_int = (int*)va_arg( args, int * ); pi_int = (int*)va_arg( args, int * );
*pi_int = SATELLITE_READ_ONCE * TS_PACKET_SIZE; *pi_int = DVB_READ_ONCE * TS_PACKET_SIZE;
break; break;
case ACCESS_GET_PTS_DELAY: case ACCESS_GET_PTS_DELAY:
...@@ -405,26 +405,16 @@ static int Control( access_t *p_access, int i_query, va_list args ) ...@@ -405,26 +405,16 @@ static int Control( access_t *p_access, int i_query, va_list args )
break; break;
case ACCESS_SET_PRIVATE_ID_CA: case ACCESS_SET_PRIVATE_ID_CA:
if ( p_sys->b_cam ) {
{ uint8_t **pp_capmts;
int i_program; int i_nb_capmts;
uint16_t i_vpid, i_apid1, i_apid2, i_apid3;
uint8_t i_cad_length;
uint8_t *p_cad;
i_program = (int)va_arg( args, int );
i_vpid = (int16_t)va_arg( args, int );
i_apid1 = (uint16_t)va_arg( args, int );
i_apid2 = (uint16_t)va_arg( args, int );
i_apid3 = (uint16_t)va_arg( args, int );
i_cad_length = (uint8_t)va_arg( args, int );
p_cad = (uint8_t *)va_arg( args, uint8_t * );
E_(CAMSet)( p_access, i_program, i_vpid, i_apid1, i_apid2,
i_apid3, i_cad_length, p_cad );
}
break;
pp_capmts = (uint8_t **)va_arg( args, uint8_t ** );
i_nb_capmts = (int)va_arg( args, int );
E_(CAMSet)( p_access, pp_capmts, i_nb_capmts );
break;
}
default: default:
msg_Warn( p_access, "unimplemented query in control" ); msg_Warn( p_access, "unimplemented query in control" );
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -509,7 +499,6 @@ static void VarInit( access_t *p_access ) ...@@ -509,7 +499,6 @@ static void VarInit( access_t *p_access )
/* */ /* */
var_Create( p_access, "dvb-adapter", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Create( p_access, "dvb-adapter", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Create( p_access, "dvb-device", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-cam", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-frequency", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Create( p_access, "dvb-frequency", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-inversion", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Create( p_access, "dvb-inversion", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Create( p_access, "dvb-probe", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); var_Create( p_access, "dvb-probe", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
...@@ -575,7 +564,6 @@ static int ParseMRL( access_t *p_access ) ...@@ -575,7 +564,6 @@ static int ParseMRL( access_t *p_access )
{ {
GET_OPTION_INT("adapter") GET_OPTION_INT("adapter")
else GET_OPTION_INT("device") else GET_OPTION_INT("device")
else GET_OPTION_BOOL("cam")
else GET_OPTION_INT("frequency") else GET_OPTION_INT("frequency")
else GET_OPTION_INT("inversion") else GET_OPTION_INT("inversion")
else GET_OPTION_BOOL("probe") else GET_OPTION_BOOL("probe")
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define DMX "/dev/dvb/adapter%d/demux%d" #define DMX "/dev/dvb/adapter%d/demux%d"
#define FRONTEND "/dev/dvb/adapter%d/frontend%d" #define FRONTEND "/dev/dvb/adapter%d/frontend%d"
#define DVR "/dev/dvb/adapter%d/dvr%d" #define DVR "/dev/dvb/adapter%d/dvr%d"
#define CA "/dev/dvb/adapter%d/ca%d"
/***************************************************************************** /*****************************************************************************
* Local structures * Local structures
...@@ -43,7 +44,19 @@ typedef struct ...@@ -43,7 +44,19 @@ typedef struct
typedef struct frontend_t frontend_t; typedef struct frontend_t frontend_t;
#define MAX_DEMUX 24 typedef struct
{
int i_slot;
int i_resource_id;
void (* pf_handle)( access_t *, int, uint8_t *, int );
void (* pf_close)( access_t *, int );
void (* pf_manage)( access_t *, int );
void *p_sys;
} en50221_session_t;
#define MAX_DEMUX 48
#define MAX_CI_SLOTS 16
#define MAX_SESSIONS 32
struct access_sys_t struct access_sys_t
{ {
...@@ -51,8 +64,16 @@ struct access_sys_t ...@@ -51,8 +64,16 @@ struct access_sys_t
demux_handle_t p_demux_handles[MAX_DEMUX]; demux_handle_t p_demux_handles[MAX_DEMUX];
frontend_t *p_frontend; frontend_t *p_frontend;
vlc_bool_t b_budget_mode; vlc_bool_t b_budget_mode;
vlc_bool_t b_cam;
int i_cam_handle; /* CA management */
int i_ca_handle;
int i_nb_slots;
vlc_bool_t pb_active_slot[MAX_CI_SLOTS];
vlc_bool_t pb_tc_has_data[MAX_CI_SLOTS];
en50221_session_t p_sessions[MAX_SESSIONS];
mtime_t i_ca_timeout, i_ca_next_event;
uint8_t **pp_capmts;
int i_nb_capmts;
}; };
#define VIDEO0_TYPE 1 #define VIDEO0_TYPE 1
...@@ -77,6 +98,12 @@ int E_(DVROpen)( access_t * ); ...@@ -77,6 +98,12 @@ int E_(DVROpen)( access_t * );
void E_(DVRClose)( access_t * ); void E_(DVRClose)( access_t * );
int E_(CAMOpen)( access_t * ); int E_(CAMOpen)( access_t * );
int E_(CAMSet)( access_t *, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, int E_(CAMPoll)( access_t * );
uint16_t, uint8_t * ); int E_(CAMSet)( access_t *, uint8_t **, int );
void E_(CAMClose)( access_t * ); void E_(CAMClose)( access_t * );
int E_(en50221_Init)( access_t * );
int E_(en50221_Poll)( access_t * );
int E_(en50221_SetCAPMT)( access_t *, uint8_t **, int );
void E_(en50221_End)( access_t * );
This diff is collapsed.
/***************************************************************************** /*****************************************************************************
* dvb.c : functions to control a DVB card under Linux with v4l2 * linux_dvb.c : functions to control a DVB card under Linux with v4l2
***************************************************************************** *****************************************************************************
* Copyright (C) 1998-2004 VideoLAN * Copyright (C) 1998-2004 VideoLAN
* *
...@@ -42,13 +42,12 @@ ...@@ -42,13 +42,12 @@
#include <linux/dvb/version.h> #include <linux/dvb/version.h>
#include <linux/dvb/dmx.h> #include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h> #include <linux/dvb/frontend.h>
#include <linux/dvb/ca.h>
#include <linux/errno.h>
#include "dvb.h" #include "dvb.h"
#include "network.h"
#define DMX_BUFFER_SIZE (1024 * 1024) #define DMX_BUFFER_SIZE (1024 * 1024)
#define CA_MAX_STATE_RETRY 5
/* /*
* Frontends * Frontends
...@@ -1108,60 +1107,121 @@ void E_(DVRClose)( access_t * p_access ) ...@@ -1108,60 +1107,121 @@ void E_(DVRClose)( access_t * p_access )
/* /*
* CAM device * CAM device
*
* This uses the external cam_set program from libdvb-0.5.4
*/ */
/***************************************************************************** /*****************************************************************************
* CAMOpen : * CAMOpen :
*****************************************************************************/ *****************************************************************************/
int E_(CAMOpen)( access_t * p_access ) int E_(CAMOpen)( access_t *p_access )
{ {
access_sys_t *p_sys = p_access->p_sys; access_sys_t *p_sys = p_access->p_sys;
char ca[128];
int i_adapter, i_device, i_slot, i_active_slots = 0;
ca_caps_t caps;
i_adapter = var_GetInteger( p_access, "dvb-adapter" );
i_device = var_GetInteger( p_access, "dvb-device" );
if( snprintf( ca, sizeof(ca), CA, i_adapter, i_device ) >= (int)sizeof(ca) )
{
msg_Err( p_access, "snprintf() truncated string for CA" );
ca[sizeof(ca) - 1] = '\0';
}
msg_Dbg( p_access, "Opening device %s", ca );
if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
{
msg_Err( p_access, "CAMInit: opening device failed (%s)",
strerror(errno) );
return VLC_EGENERIC;
}
if ( ioctl( p_sys->i_ca_handle, CA_GET_CAP, &caps ) != 0
|| caps.slot_num == 0 || caps.slot_type != CA_CI_LINK )
{
msg_Err( p_access, "CAMInit: no compatible CAM module" );
close( p_sys->i_ca_handle );
p_sys->i_ca_handle = 0;
return VLC_EGENERIC;
}
p_sys->i_nb_slots = caps.slot_num;
memset( p_sys->pb_active_slot, 0, sizeof(vlc_bool_t) * MAX_CI_SLOTS );
for ( i_slot = 0; i_slot < p_sys->i_nb_slots; i_slot++ )
{
ca_slot_info_t sinfo;
int i;
if ( ioctl( p_sys->i_ca_handle, CA_RESET, 1 << i_slot) != 0 )
{
msg_Err( p_access, "CAMInit: couldn't reset slot %d", i_slot );
continue;
}
for ( i = 0; i < CA_MAX_STATE_RETRY; i++ )
{
msleep(100000);
sinfo.num = i_slot;
if ( ioctl( p_sys->i_ca_handle, CA_GET_SLOT_INFO, &sinfo ) != 0 )
{
msg_Err( p_access, "CAMInit: couldn't get info on slot %d",
i_slot );
continue;
}
if ( sinfo.flags & CA_CI_MODULE_READY )
{
p_sys->pb_active_slot[i_slot] = VLC_TRUE;
}
}
}
p_sys->i_cam_handle = net_OpenTCP( p_access, "localhost", 4711 ); i_active_slots = E_(en50221_Init)( p_access );
if ( p_sys->i_cam_handle < 0 )
msg_Dbg( p_access, "CAMInit: found a CI handler with %d slots, %d active",
p_sys->i_nb_slots, i_active_slots );
if ( !i_active_slots )
{ {
return -VLC_EGENERIC; close( p_sys->i_ca_handle );
p_sys->i_ca_handle = 0;
return VLC_EGENERIC;
} }
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/***************************************************************************** /*****************************************************************************
* CAMSet : * CAMPoll :
*****************************************************************************/ *****************************************************************************/
int E_(CAMSet)( access_t * p_access, uint16_t i_program, uint16_t i_vpid, int E_(CAMPoll)( access_t * p_access )
uint16_t i_apid1, uint16_t i_apid2, uint16_t i_apid3,
uint16_t i_cad_length, uint8_t *p_cad )
{ {
access_sys_t *p_sys = p_access->p_sys; access_sys_t *p_sys = p_access->p_sys;
uint8_t p_str[12];
memcpy( p_str, &i_program, 2 );
memcpy( p_str + 2, &i_vpid, 2 );
memcpy( p_str + 4, &i_apid1, 2 );
memcpy( p_str + 6, &i_apid2, 2 );
memcpy( p_str + 8, &i_apid3, 2 );
memcpy( p_str + 10, &i_cad_length, 2 );
if ( net_Write( p_access, p_sys->i_cam_handle, p_str, 12 ) != 12 ) if ( p_sys->i_ca_handle == 0 )
{ {
msg_Err( p_access, "write 1 failed (%s)", strerror(errno) ); return VLC_EGENERIC;
return -VLC_EGENERIC;
} }
if ( i_cad_length ) return E_(en50221_Poll)( p_access );
}
/*****************************************************************************
* CAMSet :
*****************************************************************************/
int E_(CAMSet)( access_t * p_access, uint8_t **pp_capmts, int i_nb_capmts )
{
access_sys_t *p_sys = p_access->p_sys;
if ( p_sys->i_ca_handle == 0 )
{ {
if ( net_Write( p_access, p_sys->i_cam_handle, p_cad, i_cad_length ) return VLC_EGENERIC;
!= i_cad_length )
{
msg_Err( p_access, "write 2 failed (%s) %d", strerror(errno),
i_cad_length );
return -VLC_EGENERIC;
}
} }
E_(en50221_SetCAPMT)( p_access, pp_capmts, i_nb_capmts );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -1172,9 +1232,11 @@ void E_(CAMClose)( access_t * p_access ) ...@@ -1172,9 +1232,11 @@ void E_(CAMClose)( access_t * p_access )
{ {
access_sys_t *p_sys = p_access->p_sys; access_sys_t *p_sys = p_access->p_sys;
if ( p_sys->i_cam_handle ) E_(en50221_End)( p_access );
if ( p_sys->i_ca_handle )
{ {
close( p_sys->i_cam_handle ); close( p_sys->i_ca_handle );
} }
} }
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment