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 = \
access.c \
linux_dvb.c \
en50221.c \
dvb.h \
$(NULL)
......@@ -58,9 +58,6 @@ static void Close( vlc_object_t *p_this );
#define DEVICE_TEXT N_("Device number to use on adapter")
#define DEVICE_LONGTEXT ""
#define CAM_TEXT N_("Use CAM")
#define CAM_LONGTEXT ""
#define FREQ_TEXT N_("Transponder/multiplex frequency")
#define FREQ_LONGTEXT N_("In kHz for DVB-S or Hz for DVB-C/T")
......@@ -131,7 +128,6 @@ vlc_module_begin();
VLC_FALSE );
add_integer( "dvb-device", 0, NULL, DEVICE_TEXT, DEVICE_LONGTEXT,
VLC_TRUE );
add_bool( "dvb-cam", 0, NULL, CAM_TEXT, CAM_LONGTEXT, VLC_FALSE );
add_integer( "dvb-frequency", 11954000, NULL, FREQ_TEXT, FREQ_LONGTEXT,
VLC_FALSE );
add_integer( "dvb-inversion", 2, NULL, INVERSION_TEXT, INVERSION_LONGTEXT,
......@@ -190,7 +186,7 @@ vlc_module_end();
static block_t *Block( access_t * );
static int Control( access_t *, int, va_list );
#define SATELLITE_READ_ONCE 3
#define DVB_READ_ONCE 3
#define TS_PACKET_SIZE 188
static void FilterUnset( access_t *, int i_max );
......@@ -274,13 +270,7 @@ static int Open( vlc_object_t *p_this )
FilterSet( p_access, 0x0, OTHER_TYPE );
}
p_sys->b_cam = var_GetBool( p_access, "dvb-cam" );
if ( p_sys->b_cam )
{
msg_Dbg( p_access, "initing CAM..." );
if ( E_(CAMOpen)( p_access ) < 0 )
p_sys->b_cam = VLC_FALSE;
}
E_(CAMOpen)( p_access );
return VLC_SUCCESS;
}
......@@ -297,8 +287,6 @@ static void Close( vlc_object_t *p_this )
E_(DVRClose)( p_access );
E_(FrontendClose)( p_access );
if ( p_sys->b_cam )
E_(CAMClose)( p_access );
free( p_sys );
......@@ -310,10 +298,13 @@ static void Close( vlc_object_t *p_this )
static block_t *Block( access_t *p_access )
{
access_sys_t *p_sys = p_access->p_sys;
block_t *p_block;
for ( ; ; )
{
struct timeval timeout;
fd_set fds;
int i_ret;
block_t *p_block;
/* Initialize file descriptor set */
FD_ZERO( &fds );
......@@ -324,17 +315,13 @@ static block_t *Block( access_t *p_access )
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) )
{
FD_ZERO( &fds );
FD_SET( p_sys->i_handle, &fds );
timeout.tv_sec = 0;
timeout.tv_usec = 500000;
i_ret = select( p_sys->i_handle + 1, &fds, NULL, NULL, &timeout );
if( p_access->b_die )
if ( p_access->b_die )
return NULL;
}
if ( i_ret < 0 && errno == EINTR )
continue;
if ( i_ret < 0 )
{
......@@ -342,8 +329,21 @@ static block_t *Block( access_t *p_access )
return NULL;
}
p_block = block_New( p_access, SATELLITE_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_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, DVB_READ_ONCE * TS_PACKET_SIZE );
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) );
block_Release( p_block );
......@@ -376,7 +376,7 @@ static int Control( access_t *p_access, int i_query, va_list args )
/* */
case ACCESS_GET_MTU:
pi_int = (int*)va_arg( args, int * );
*pi_int = SATELLITE_READ_ONCE * TS_PACKET_SIZE;
*pi_int = DVB_READ_ONCE * TS_PACKET_SIZE;
break;
case ACCESS_GET_PTS_DELAY:
......@@ -405,26 +405,16 @@ static int Control( access_t *p_access, int i_query, va_list args )
break;
case ACCESS_SET_PRIVATE_ID_CA:
if ( p_sys->b_cam )
{
int i_program;
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;
uint8_t **pp_capmts;
int i_nb_capmts;
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:
msg_Warn( p_access, "unimplemented query in control" );
return VLC_EGENERIC;
......@@ -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-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-inversion", VLC_VAR_INTEGER | 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 )
{
GET_OPTION_INT("adapter")
else GET_OPTION_INT("device")
else GET_OPTION_BOOL("cam")
else GET_OPTION_INT("frequency")
else GET_OPTION_INT("inversion")
else GET_OPTION_BOOL("probe")
......
......@@ -30,6 +30,7 @@
#define DMX "/dev/dvb/adapter%d/demux%d"
#define FRONTEND "/dev/dvb/adapter%d/frontend%d"
#define DVR "/dev/dvb/adapter%d/dvr%d"
#define CA "/dev/dvb/adapter%d/ca%d"
/*****************************************************************************
* Local structures
......@@ -43,7 +44,19 @@ typedef struct
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
{
......@@ -51,8 +64,16 @@ struct access_sys_t
demux_handle_t p_demux_handles[MAX_DEMUX];
frontend_t *p_frontend;
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
......@@ -77,6 +98,12 @@ int E_(DVROpen)( access_t * );
void E_(DVRClose)( access_t * );
int E_(CAMOpen)( access_t * );
int E_(CAMSet)( access_t *, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t,
uint16_t, uint8_t * );
int E_(CAMPoll)( access_t * );
int E_(CAMSet)( access_t *, uint8_t **, int );
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
*
......@@ -42,13 +42,12 @@
#include <linux/dvb/version.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/errno.h>
#include <linux/dvb/ca.h>
#include "dvb.h"
#include "network.h"
#define DMX_BUFFER_SIZE (1024 * 1024)
#define CA_MAX_STATE_RETRY 5
/*
* Frontends
......@@ -1108,60 +1107,121 @@ void E_(DVRClose)( access_t * p_access )
/*
* CAM device
*
* This uses the external cam_set program from libdvb-0.5.4
*/
/*****************************************************************************
* CAMOpen :
*****************************************************************************/
int E_(CAMOpen)( access_t * p_access )
int E_(CAMOpen)( access_t *p_access )
{
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';
}
p_sys->i_cam_handle = net_OpenTCP( p_access, "localhost", 4711 );
if ( p_sys->i_cam_handle < 0 )
msg_Dbg( p_access, "Opening device %s", ca );
if( (p_sys->i_ca_handle = open(ca, O_RDWR | O_NONBLOCK)) < 0 )
{
return -VLC_EGENERIC;
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;
}
}
}
i_active_slots = E_(en50221_Init)( p_access );
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 )
{
close( p_sys->i_ca_handle );
p_sys->i_ca_handle = 0;
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* CAMSet :
* CAMPoll :
*****************************************************************************/
int E_(CAMSet)( access_t * p_access, uint16_t i_program, uint16_t i_vpid,
uint16_t i_apid1, uint16_t i_apid2, uint16_t i_apid3,
uint16_t i_cad_length, uint8_t *p_cad )
int E_(CAMPoll)( access_t * p_access )
{
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 )
{
if ( net_Write( p_access, p_sys->i_cam_handle, p_cad, i_cad_length )
!= 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 )
{
msg_Err( p_access, "write 2 failed (%s) %d", strerror(errno),
i_cad_length );
return -VLC_EGENERIC;
}
return VLC_EGENERIC;
}
E_(en50221_SetCAPMT)( p_access, pp_capmts, i_nb_capmts );
return VLC_SUCCESS;
}
......@@ -1172,9 +1232,11 @@ void E_(CAMClose)( access_t * p_access )
{
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