Commit 4986db7e authored by Christophe Massiot's avatar Christophe Massiot

* asi.c, asi.h: Support for Computer Modules ASI input cards (-A).

parent 35c442a3
...@@ -7,12 +7,12 @@ CFLAGS += -I/usr/src/kernel/linux-2.6.29.1/include ...@@ -7,12 +7,12 @@ CFLAGS += -I/usr/src/kernel/linux-2.6.29.1/include
LDFLAGS += -lrt LDFLAGS += -lrt
LDFLAGS_DVBLAST += -ldvbpsi -lpthread LDFLAGS_DVBLAST += -ldvbpsi -lpthread
OBJ_DVBLAST = dvblast.o util.o dvb.o udp.o demux.o output.o en50221.o comm.o OBJ_DVBLAST = dvblast.o util.o dvb.o udp.o asi.o demux.o output.o en50221.o comm.o
OBJ_DVBLASTCTL = util.o dvblastctl.o OBJ_DVBLASTCTL = util.o dvblastctl.o
all: dvblast dvblastctl all: dvblast dvblastctl
$(OBJ_DVBLAST) $(OBJ_DVBLASTCTL): Makefile dvblast.h en50221.h comm.h version.h $(OBJ_DVBLAST) $(OBJ_DVBLASTCTL): Makefile dvblast.h en50221.h comm.h version.h asi.h
dvblast: $(OBJ_DVBLAST) dvblast: $(OBJ_DVBLAST)
$(CC) -o $@ $(OBJ_DVBLAST) $(LDFLAGS_DVBLAST) $(LDFLAGS) $(CC) -o $@ $(OBJ_DVBLAST) $(LDFLAGS_DVBLAST) $(LDFLAGS)
......
/*****************************************************************************
* asi.c: support for Computer Modules ASI cards
*****************************************************************************
* Copyright (C) 2004, 2009 VideoLAN
* $Id: asi.c 9 2007-03-15 16:58:05Z cmassiot $
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include "asi.h"
#include "dvblast.h"
/*
* The problem with hardware filtering is that on startup, when you only
* set a filter on PID 0, it can take a very long time for a large buffer
* (typically ~100 TS packets) to fill up. And the buffer size cannot be
* adjusted afer startup. --Meuuh
*/
#undef USE_HARDWARE_FILTERING
/*****************************************************************************
* Local declarations
*****************************************************************************/
#define ASI_DEVICE "/dev/asirx%u"
#define ASI_TIMESTAMPS_FILE "/sys/class/asi/asirx%u/timestamps"
#define ASI_BUFSIZE_FILE "/sys/class/asi/asirx%u/bufsize"
static int i_handle;
static int i_bufsize;
static uint8_t p_pid_filter[8192 / 8];
/*****************************************************************************
* Local helpers
*****************************************************************************/
#define MAXLEN 256
static int ReadULSysfs( const char *psz_fmt, unsigned int i_link )
{
char psz_file[MAXLEN], psz_data[MAXLEN];
char *psz_tmp;
int i_fd;
ssize_t i_ret;
unsigned int i_data;
snprintf( psz_file, sizeof(psz_file), psz_fmt, i_link );
psz_file[sizeof(psz_file) - 1] = '\0';
if ( (i_fd = open( psz_file, O_RDONLY )) < 0 )
return i_fd;
i_ret = read( i_fd, psz_data, sizeof(psz_data) );
close( i_fd );
if ( i_ret < 0 )
return i_ret;
i_data = strtoul( psz_data, &psz_tmp, 0 );
if ( *psz_tmp != '\n' )
return -1;
return i_data;
}
static ssize_t WriteULSysfs( const char *psz_fmt, unsigned int i_link,
unsigned int i_buf )
{
char psz_file[MAXLEN], psz_data[MAXLEN];
int i_fd;
ssize_t i_ret;
snprintf( psz_file, sizeof(psz_file), psz_fmt, i_link );
psz_file[sizeof(psz_file) - 1] = '\0';
snprintf( psz_data, sizeof(psz_data), "%u\n", i_buf );
psz_file[sizeof(psz_data) - 1] = '\0';
if ( (i_fd = open( psz_file, O_WRONLY )) < 0 )
return i_fd;
i_ret = write( i_fd, psz_data, strlen(psz_data) + 1 );
close( i_fd );
return i_ret;
}
/*****************************************************************************
* asi_Open
*****************************************************************************/
void asi_Open( void )
{
char psz_dev[MAXLEN];
/* No timestamp - we wouldn't know what to do with them */
if ( WriteULSysfs( ASI_TIMESTAMPS_FILE, i_asi_adapter, 0 ) < 0 )
{
msg_Err( NULL, "couldn't write file " ASI_TIMESTAMPS_FILE,
i_asi_adapter );
exit(EXIT_FAILURE);
}
if ( (i_bufsize = ReadULSysfs( ASI_BUFSIZE_FILE, i_asi_adapter )) < 0 )
{
msg_Err( NULL, "couldn't read file " ASI_BUFSIZE_FILE, i_asi_adapter );
exit(EXIT_FAILURE);
}
if ( i_bufsize % TS_SIZE )
{
msg_Err( NULL, ASI_BUFSIZE_FILE " must be a multiple of 188",
i_asi_adapter );
exit(EXIT_FAILURE);
}
snprintf( psz_dev, sizeof(psz_dev), ASI_DEVICE, i_asi_adapter );
psz_dev[sizeof(psz_dev) - 1] = '\0';
if ( (i_handle = open( psz_dev, O_RDONLY, 0 )) < 0 )
{
msg_Err( NULL, "couldn't open device " ASI_DEVICE " (%s)",
i_asi_adapter, strerror(errno) );
exit(EXIT_FAILURE);
}
#ifdef USE_HARDWARE_FILTERING
memset( p_pid_filter, 0x0, sizeof(p_pid_filter) );
#else
memset( p_pid_filter, 0xff, sizeof(p_pid_filter) );
p_pid_filter[8191 / 8] &= ~(0x01 << (8191 % 8)); /* padding */
#endif
if ( ioctl( i_handle, ASI_IOC_RXSETPF, p_pid_filter ) < 0 )
{
msg_Warn( NULL, "couldn't filter padding" );
}
fsync( i_handle );
}
/*****************************************************************************
* asi_Read : read packets from the device
*****************************************************************************/
block_t *asi_Read( void )
{
int i, i_len;
struct iovec p_iov[i_bufsize / TS_SIZE];
block_t *p_ts, **pp_current = &p_ts;
for ( ; ; )
{
struct pollfd pfd;
pfd.fd = i_handle;
pfd.events = POLLIN | POLLPRI;
if ( poll(&pfd, 1, -1) < 0 )
{
msg_Err( NULL, "couldn't poll from device " ASI_DEVICE " (%s)",
i_asi_adapter, strerror(errno) );
continue;
}
if ( (pfd.revents & POLLPRI) )
{
unsigned int i_val;
if ( ioctl(i_handle, ASI_IOC_RXGETEVENTS, &i_val) < 0 )
msg_Err( NULL, "couldn't RXGETEVENTS (%s)", strerror(errno) );
else
{
if ( i_val & ASI_EVENT_RX_BUFFER )
msg_Warn( NULL, "driver receive buffer queue overrun" );
if ( i_val & ASI_EVENT_RX_FIFO )
msg_Warn( NULL, "onboard receive FIFO overrun" );
if ( i_val & ASI_EVENT_RX_CARRIER )
msg_Warn( NULL, "carrier status change" );
if ( i_val & ASI_EVENT_RX_LOS )
msg_Warn( NULL, "loss of packet synchronization" );
if ( i_val & ASI_EVENT_RX_AOS )
msg_Warn( NULL, "acquisition of packet synchronization" );
if ( i_val & ASI_EVENT_RX_DATA )
msg_Warn( NULL, "receive data status change" );
}
}
if ( (pfd.revents & POLLIN) )
break;
}
for ( i = 0; i < i_bufsize / TS_SIZE; i++ )
{
*pp_current = block_New();
p_iov[i].iov_base = (*pp_current)->p_ts;
p_iov[i].iov_len = TS_SIZE;
pp_current = &(*pp_current)->p_next;
}
if ( (i_len = readv(i_handle, p_iov, i_bufsize / TS_SIZE)) < 0 )
{
msg_Err( NULL, "couldn't read from device " ASI_DEVICE " (%s)",
i_asi_adapter, strerror(errno) );
i_len = 0;
}
i_len /= TS_SIZE;
pp_current = &p_ts;
while ( i_len && *pp_current )
{
pp_current = &(*pp_current)->p_next;
i_len--;
}
if ( *pp_current )
msg_Dbg( NULL, "partial buffer received" );
block_DeleteChain( *pp_current );
*pp_current = NULL;
return p_ts;
}
/*****************************************************************************
* asi_SetFilter
*****************************************************************************/
int asi_SetFilter( uint16_t i_pid )
{
#ifdef USE_HARDWARE_FILTERING
p_pid_filter[ i_pid / 8 ] |= (0x01 << (i_pid % 8));
if ( ioctl( i_handle, ASI_IOC_RXSETPF, p_pid_filter ) < 0 )
msg_Warn( NULL, "couldn't add filter on PID %u", i_pid );
return 1;
#else
return -1;
#endif
}
/*****************************************************************************
* asi_UnsetFilter: normally never called
*****************************************************************************/
void asi_UnsetFilter( int i_fd, uint16_t i_pid )
{
#ifdef USE_HARDWARE_FILTERING
p_pid_filter[ i_pid / 8 ] &= ~(0x01 << (i_pid % 8));
if ( ioctl( i_handle, ASI_IOC_RXSETPF, p_pid_filter ) < 0 )
msg_Warn( NULL, "couldn't remove filter on PID %u", i_pid );
#endif
}
This diff is collapsed.
...@@ -66,6 +66,7 @@ int i_verbose = DEFAULT_VERBOSITY; ...@@ -66,6 +66,7 @@ int i_verbose = DEFAULT_VERBOSITY;
uint16_t i_src_port = DEFAULT_PORT; uint16_t i_src_port = DEFAULT_PORT;
in_addr_t i_src_addr = { 0 }; in_addr_t i_src_addr = { 0 };
int b_src_rawudp = 0; int b_src_rawudp = 0;
int i_asi_adapter = 0;
void (*pf_Open)( void ) = NULL; void (*pf_Open)( void ) = NULL;
block_t * (*pf_Read)( void ) = NULL; block_t * (*pf_Read)( void ) = NULL;
...@@ -219,7 +220,7 @@ static void DisplayVersion() ...@@ -219,7 +220,7 @@ static void DisplayVersion()
*****************************************************************************/ *****************************************************************************/
void usage() void usage()
{ {
msg_Raw( NULL, "Usage: dvblast [-q] [-c <config file>] [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] [-i <RT priority>] [-a <adapter>] [-n <frontend number>] [-S <diseqc>] [-f <frequency>|-D <src mcast>:<port>] [-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-m <modulation] [-u] [-W] [-U] [-d <dest IP:port>] [-e] [-T]" ); msg_Raw( NULL, "Usage: dvblast [-q] [-c <config file>] [-r <remote socket>] [-t <ttl>] [-o <SSRC IP>] [-i <RT priority>] [-a <adapter>] [-n <frontend number>] [-S <diseqc>] [-f <frequency>|-D <src mcast>:<port>|-A <ASI adapter>] [-s <symbol rate>] [-v <0|13|18>] [-p] [-b <bandwidth>] [-m <modulation] [-u] [-W] [-U] [-d <dest IP:port>] [-e] [-T]" );
msg_Raw( NULL, " -q: be quiet (less verbosity, repeat or use number for even quieter)" ); msg_Raw( NULL, " -q: be quiet (less verbosity, repeat or use number for even quieter)" );
msg_Raw( NULL, " -v: voltage to apply to the LNB (QPSK)" ); msg_Raw( NULL, " -v: voltage to apply to the LNB (QPSK)" );
msg_Raw( NULL, " -p: force 22kHz pulses for high-band selection (DVB-S)" ); msg_Raw( NULL, " -p: force 22kHz pulses for high-band selection (DVB-S)" );
...@@ -232,6 +233,7 @@ void usage() ...@@ -232,6 +233,7 @@ void usage()
msg_Raw( NULL, " -U: use raw UDP rather than RTP (required by some IPTV set top boxes)" ); msg_Raw( NULL, " -U: use raw UDP rather than RTP (required by some IPTV set top boxes)" );
msg_Raw( NULL, " -d: duplicate all received packets to a given destination" ); msg_Raw( NULL, " -d: duplicate all received packets to a given destination" );
msg_Raw( NULL, " -D: read packets from a multicast address instead of a DVB card" ); msg_Raw( NULL, " -D: read packets from a multicast address instead of a DVB card" );
msg_Raw( NULL, " -A: read packets from an ASI adapter (0-n)" );
msg_Raw( NULL, " -e: enable EPG pass through (EIT data)" ); msg_Raw( NULL, " -e: enable EPG pass through (EIT data)" );
msg_Raw( NULL, " -T: generate unique TS ID for each program" ); msg_Raw( NULL, " -T: generate unique TS ID for each program" );
msg_Raw( NULL, " -h: display this full help" ); msg_Raw( NULL, " -h: display this full help" );
...@@ -250,7 +252,7 @@ int main( int i_argc, char **pp_argv ) ...@@ -250,7 +252,7 @@ int main( int i_argc, char **pp_argv )
if ( i_argc == 1 ) if ( i_argc == 1 )
usage(); usage();
while ( ( c = getopt(i_argc, pp_argv, "q::c:r:t:o:i:a:n:f:s:S:v:pb:m:uWUTd:D:ehV")) != -1 ) while ( ( c = getopt(i_argc, pp_argv, "q::c:r:t:o:i:a:n:f:s:S:v:pb:m:uWUTd:D:A:ehV")) != -1 )
{ {
switch ( c ) switch ( c )
{ {
...@@ -410,6 +412,21 @@ int main( int i_argc, char **pp_argv ) ...@@ -410,6 +412,21 @@ int main( int i_argc, char **pp_argv )
break; break;
} }
case 'A':
i_asi_adapter = strtol( optarg, NULL, 0 );
if ( pf_Open != NULL )
usage();
if ( psz_srv_socket != NULL )
{
msg_Err( NULL, "-r is only available for linux-dvb input" );
usage();
}
pf_Open = asi_Open;
pf_Read = asi_Read;
pf_SetFilter = asi_SetFilter;
pf_UnsetFilter = asi_UnsetFilter;
break;
case 'e': case 'e':
b_enable_epg = 1; b_enable_epg = 1;
break; break;
......
...@@ -105,6 +105,7 @@ extern int i_comm_fd; ...@@ -105,6 +105,7 @@ extern int i_comm_fd;
extern uint16_t i_src_port; extern uint16_t i_src_port;
extern in_addr_t i_src_addr; extern in_addr_t i_src_addr;
extern int b_src_rawudp; extern int b_src_rawudp;
extern int i_asi_adapter;
extern void (*pf_Open)( void ); extern void (*pf_Open)( void );
extern block_t * (*pf_Read)( void ); extern block_t * (*pf_Read)( void );
...@@ -134,6 +135,11 @@ block_t * udp_Read( void ); ...@@ -134,6 +135,11 @@ block_t * udp_Read( void );
int udp_SetFilter( uint16_t i_pid ); int udp_SetFilter( uint16_t i_pid );
void udp_UnsetFilter( int i_fd, uint16_t i_pid ); void udp_UnsetFilter( int i_fd, uint16_t i_pid );
void asi_Open( void );
block_t * asi_Read( void );
int asi_SetFilter( uint16_t i_pid );
void asi_UnsetFilter( int i_fd, uint16_t i_pid );
void demux_Open( void ); void demux_Open( void );
void demux_Run( void ); void demux_Run( void );
void demux_Change( output_t *p_output, uint16_t i_sid, void demux_Change( output_t *p_output, uint16_t i_sid,
......
...@@ -136,6 +136,8 @@ block_t *udp_Read( void ) ...@@ -136,6 +136,8 @@ block_t *udp_Read( void )
i_len--; i_len--;
} }
if ( *pp_current )
msg_Dbg( NULL, "partial buffer received" );
block_DeleteChain( *pp_current ); block_DeleteChain( *pp_current );
*pp_current = NULL; *pp_current = NULL;
......
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