2011-01-25 17:01:00 -03:00
/*
* altera - ci . c
*
* CI driver in conjunction with NetUp Dual DVB - T / C RF CI card
*
* Copyright ( C ) 2010 , 2011 NetUP Inc .
* Copyright ( C ) 2010 , 2011 Igor M . Liplianin < liplianin @ netup . ru >
*
* 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
* currently cx23885 GPIO ' s used .
* GPIO - 0 ~ INT in
* GPIO - 1 TMS out
* GPIO - 2 ~ reset chips out
* GPIO - 3 to GPIO - 10 data / addr for CA in / out
* GPIO - 11 ~ CS out
* GPIO - 12 AD_RG out
* GPIO - 13 ~ WR out
* GPIO - 14 ~ RD out
* GPIO - 15 ~ RDY in
* GPIO - 16 TCK out
* GPIO - 17 TDO in
* GPIO - 18 TDI out
*/
/*
* Bit definitions for MC417_RWD and MC417_OEN registers
* bits 31 - 16
* + - - - - - - - - - - - +
* | Reserved |
* + - - - - - - - - - - - +
* bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
* + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
* | TDI | TDO | TCK | RDY # | # RD | # WR | AD_RG | # CS |
* + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
* bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
* + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
* | DATA7 | DATA6 | DATA5 | DATA4 | DATA3 | DATA2 | DATA1 | DATA0 |
* + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - + - - - - - - - +
*/
# include <linux/version.h>
# include <media/videobuf-dma-sg.h>
# include <media/videobuf-dvb.h>
# include "altera-ci.h"
# include "dvb_ca_en50221.h"
/* FPGA regs */
# define NETUP_CI_INT_CTRL 0x00
# define NETUP_CI_BUSCTRL2 0x01
# define NETUP_CI_ADDR0 0x04
# define NETUP_CI_ADDR1 0x05
# define NETUP_CI_DATA 0x06
# define NETUP_CI_BUSCTRL 0x07
# define NETUP_CI_PID_ADDR0 0x08
# define NETUP_CI_PID_ADDR1 0x09
# define NETUP_CI_PID_DATA 0x0a
# define NETUP_CI_TSA_DIV 0x0c
# define NETUP_CI_TSB_DIV 0x0d
# define NETUP_CI_REVISION 0x0f
/* const for ci op */
# define NETUP_CI_FLG_CTL 1
# define NETUP_CI_FLG_RD 1
# define NETUP_CI_FLG_AD 1
static unsigned int ci_dbg ;
module_param ( ci_dbg , int , 0644 ) ;
MODULE_PARM_DESC ( ci_dbg , " Enable CI debugging " ) ;
static unsigned int pid_dbg ;
module_param ( pid_dbg , int , 0644 ) ;
MODULE_PARM_DESC ( pid_dbg , " Enable PID filtering debugging " ) ;
MODULE_DESCRIPTION ( " altera FPGA CI module " ) ;
MODULE_AUTHOR ( " Igor M. Liplianin <liplianin@netup.ru> " ) ;
MODULE_LICENSE ( " GPL " ) ;
# define ci_dbg_print(args...) \
do { \
if ( ci_dbg ) \
printk ( KERN_DEBUG args ) ; \
} while ( 0 )
# define pid_dbg_print(args...) \
do { \
if ( pid_dbg ) \
printk ( KERN_DEBUG args ) ; \
} while ( 0 )
struct altera_ci_state ;
struct netup_hw_pid_filter ;
struct fpga_internal {
void * dev ;
struct mutex fpga_mutex ; /* two CI's on the same fpga */
struct netup_hw_pid_filter * pid_filt [ 2 ] ;
struct altera_ci_state * state [ 2 ] ;
struct work_struct work ;
int ( * fpga_rw ) ( void * dev , int flag , int data , int rw ) ;
int cis_used ;
int filts_used ;
int strt_wrk ;
} ;
/* stores all private variables for communication with CI */
struct altera_ci_state {
struct fpga_internal * internal ;
struct dvb_ca_en50221 ca ;
int status ;
int nr ;
} ;
/* stores all private variables for hardware pid filtering */
struct netup_hw_pid_filter {
struct fpga_internal * internal ;
struct dvb_demux * demux ;
/* save old functions */
int ( * start_feed ) ( struct dvb_demux_feed * feed ) ;
int ( * stop_feed ) ( struct dvb_demux_feed * feed ) ;
int status ;
int nr ;
} ;
/* internal params node */
struct fpga_inode {
/* pointer for internal params, one for each pair of CI's */
struct fpga_internal * internal ;
struct fpga_inode * next_inode ;
} ;
/* first internal params */
static struct fpga_inode * fpga_first_inode ;
/* find chip by dev */
static struct fpga_inode * find_inode ( void * dev )
{
struct fpga_inode * temp_chip = fpga_first_inode ;
if ( temp_chip = = NULL )
return temp_chip ;
/*
Search for the last fpga CI chip or
find it by dev */
while ( ( temp_chip ! = NULL ) & &
( temp_chip - > internal - > dev ! = dev ) )
temp_chip = temp_chip - > next_inode ;
return temp_chip ;
}
/* check demux */
static struct fpga_internal * check_filter ( struct fpga_internal * temp_int ,
void * demux_dev , int filt_nr )
{
if ( temp_int = = NULL )
return NULL ;
if ( ( temp_int - > pid_filt [ filt_nr ] ) = = NULL )
return NULL ;
if ( temp_int - > pid_filt [ filt_nr ] - > demux = = demux_dev )
return temp_int ;
return NULL ;
}
/* find chip by demux */
static struct fpga_inode * find_dinode ( void * demux_dev )
{
struct fpga_inode * temp_chip = fpga_first_inode ;
struct fpga_internal * temp_int ;
/*
* Search of the last fpga CI chip or
* find it by demux
*/
while ( temp_chip ! = NULL ) {
if ( temp_chip - > internal ! = NULL ) {
temp_int = temp_chip - > internal ;
if ( check_filter ( temp_int , demux_dev , 0 ) )
break ;
if ( check_filter ( temp_int , demux_dev , 1 ) )
break ;
}
temp_chip = temp_chip - > next_inode ;
}
return temp_chip ;
}
/* deallocating chip */
static void remove_inode ( struct fpga_internal * internal )
{
struct fpga_inode * prev_node = fpga_first_inode ;
struct fpga_inode * del_node = find_inode ( internal - > dev ) ;
if ( del_node ! = NULL ) {
if ( del_node = = fpga_first_inode ) {
fpga_first_inode = del_node - > next_inode ;
} else {
while ( prev_node - > next_inode ! = del_node )
prev_node = prev_node - > next_inode ;
if ( del_node - > next_inode = = NULL )
prev_node - > next_inode = NULL ;
else
prev_node - > next_inode =
prev_node - > next_inode - > next_inode ;
}
kfree ( del_node ) ;
}
}
/* allocating new chip */
static struct fpga_inode * append_internal ( struct fpga_internal * internal )
{
struct fpga_inode * new_node = fpga_first_inode ;
if ( new_node = = NULL ) {
new_node = kmalloc ( sizeof ( struct fpga_inode ) , GFP_KERNEL ) ;
fpga_first_inode = new_node ;
} else {
while ( new_node - > next_inode ! = NULL )
new_node = new_node - > next_inode ;
new_node - > next_inode =
kmalloc ( sizeof ( struct fpga_inode ) , GFP_KERNEL ) ;
if ( new_node - > next_inode ! = NULL )
new_node = new_node - > next_inode ;
else
new_node = NULL ;
}
if ( new_node ! = NULL ) {
new_node - > internal = internal ;
new_node - > next_inode = NULL ;
}
return new_node ;
}
static int netup_fpga_op_rw ( struct fpga_internal * inter , int addr ,
u8 val , u8 read )
{
inter - > fpga_rw ( inter - > dev , NETUP_CI_FLG_AD , addr , 0 ) ;
return inter - > fpga_rw ( inter - > dev , 0 , val , read ) ;
}
/* flag - mem/io, read - read/write */
int altera_ci_op_cam ( struct dvb_ca_en50221 * en50221 , int slot ,
u8 flag , u8 read , int addr , u8 val )
{
struct altera_ci_state * state = en50221 - > data ;
struct fpga_internal * inter = state - > internal ;
u8 store ;
int mem = 0 ;
if ( 0 ! = slot )
return - EINVAL ;
mutex_lock ( & inter - > fpga_mutex ) ;
netup_fpga_op_rw ( inter , NETUP_CI_ADDR0 , ( ( addr < < 1 ) & 0xfe ) , 0 ) ;
netup_fpga_op_rw ( inter , NETUP_CI_ADDR1 , ( ( addr > > 7 ) & 0x7f ) , 0 ) ;
store = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL , 0 , NETUP_CI_FLG_RD ) ;
store & = 0x3f ;
store | = ( ( state - > nr < < 7 ) | ( flag < < 6 ) ) ;
netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL , store , 0 ) ;
mem = netup_fpga_op_rw ( inter , NETUP_CI_DATA , val , read ) ;
mutex_unlock ( & inter - > fpga_mutex ) ;
ci_dbg_print ( " %s: %s: addr=[0x%02x], %s=%x \n " , __func__ ,
( read ) ? " read " : " write " , addr ,
( flag = = NETUP_CI_FLG_CTL ) ? " ctl " : " mem " ,
( read ) ? mem : val ) ;
return mem ;
}
int altera_ci_read_attribute_mem ( struct dvb_ca_en50221 * en50221 ,
int slot , int addr )
{
return altera_ci_op_cam ( en50221 , slot , 0 , NETUP_CI_FLG_RD , addr , 0 ) ;
}
int altera_ci_write_attribute_mem ( struct dvb_ca_en50221 * en50221 ,
int slot , int addr , u8 data )
{
return altera_ci_op_cam ( en50221 , slot , 0 , 0 , addr , data ) ;
}
int altera_ci_read_cam_ctl ( struct dvb_ca_en50221 * en50221 , int slot , u8 addr )
{
return altera_ci_op_cam ( en50221 , slot , NETUP_CI_FLG_CTL ,
NETUP_CI_FLG_RD , addr , 0 ) ;
}
int altera_ci_write_cam_ctl ( struct dvb_ca_en50221 * en50221 , int slot ,
u8 addr , u8 data )
{
return altera_ci_op_cam ( en50221 , slot , NETUP_CI_FLG_CTL , 0 , addr , data ) ;
}
int altera_ci_slot_reset ( struct dvb_ca_en50221 * en50221 , int slot )
{
struct altera_ci_state * state = en50221 - > data ;
struct fpga_internal * inter = state - > internal ;
/* reasonable timeout for CI reset is 10 seconds */
unsigned long t_out = jiffies + msecs_to_jiffies ( 9999 ) ;
int ret ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( 0 ! = slot )
return - EINVAL ;
mutex_lock ( & inter - > fpga_mutex ) ;
ret = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL , 0 , NETUP_CI_FLG_RD ) ;
netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL ,
ret | ( 1 < < ( 5 - state - > nr ) ) , 0 ) ;
for ( ; ; ) {
mdelay ( 50 ) ;
ret = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL ,
0 , NETUP_CI_FLG_RD ) ;
if ( ( ret & ( 1 < < ( 5 - state - > nr ) ) ) = = 0 )
break ;
if ( time_after ( jiffies , t_out ) )
break ;
}
mutex_unlock ( & inter - > fpga_mutex ) ;
ci_dbg_print ( " %s: %d msecs \n " , __func__ ,
jiffies_to_msecs ( jiffies + msecs_to_jiffies ( 9999 ) - t_out ) ) ;
return 0 ;
}
int altera_ci_slot_shutdown ( struct dvb_ca_en50221 * en50221 , int slot )
{
/* not implemented */
return 0 ;
}
int altera_ci_slot_ts_ctl ( struct dvb_ca_en50221 * en50221 , int slot )
{
struct altera_ci_state * state = en50221 - > data ;
struct fpga_internal * inter = state - > internal ;
int ret ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( 0 ! = slot )
return - EINVAL ;
mutex_lock ( & inter - > fpga_mutex ) ;
ret = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL , 0 , NETUP_CI_FLG_RD ) ;
netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL ,
ret | ( 1 < < ( 3 - state - > nr ) ) , 0 ) ;
mutex_unlock ( & inter - > fpga_mutex ) ;
return 0 ;
}
/* work handler */
static void netup_read_ci_status ( struct work_struct * work )
{
struct fpga_internal * inter =
container_of ( work , struct fpga_internal , work ) ;
int ret ;
ci_dbg_print ( " %s \n " , __func__ ) ;
mutex_lock ( & inter - > fpga_mutex ) ;
/* ack' irq */
ret = netup_fpga_op_rw ( inter , NETUP_CI_INT_CTRL , 0 , NETUP_CI_FLG_RD ) ;
ret = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL , 0 , NETUP_CI_FLG_RD ) ;
mutex_unlock ( & inter - > fpga_mutex ) ;
if ( inter - > state [ 1 ] ! = NULL ) {
inter - > state [ 1 ] - > status =
( ( ret & 1 ) = = 0 ?
DVB_CA_EN50221_POLL_CAM_PRESENT |
DVB_CA_EN50221_POLL_CAM_READY : 0 ) ;
ci_dbg_print ( " %s: setting CI[1] status = 0x%x \n " ,
__func__ , inter - > state [ 1 ] - > status ) ;
} ;
if ( inter - > state [ 0 ] ! = NULL ) {
inter - > state [ 0 ] - > status =
( ( ret & 2 ) = = 0 ?
DVB_CA_EN50221_POLL_CAM_PRESENT |
DVB_CA_EN50221_POLL_CAM_READY : 0 ) ;
ci_dbg_print ( " %s: setting CI[0] status = 0x%x \n " ,
__func__ , inter - > state [ 0 ] - > status ) ;
} ;
}
/* CI irq handler */
int altera_ci_irq ( void * dev )
{
struct fpga_inode * temp_int = NULL ;
struct fpga_internal * inter = NULL ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( dev ! = NULL ) {
temp_int = find_inode ( dev ) ;
if ( temp_int ! = NULL ) {
inter = temp_int - > internal ;
schedule_work ( & inter - > work ) ;
}
}
return 1 ;
}
EXPORT_SYMBOL ( altera_ci_irq ) ;
int altera_poll_ci_slot_status ( struct dvb_ca_en50221 * en50221 , int slot ,
int open )
{
struct altera_ci_state * state = en50221 - > data ;
if ( 0 ! = slot )
return - EINVAL ;
return state - > status ;
}
void altera_hw_filt_release ( void * main_dev , int filt_nr )
{
struct fpga_inode * temp_int = find_inode ( main_dev ) ;
struct netup_hw_pid_filter * pid_filt = NULL ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( temp_int ! = NULL ) {
pid_filt = temp_int - > internal - > pid_filt [ filt_nr - 1 ] ;
/* stored old feed controls */
pid_filt - > demux - > start_feed = pid_filt - > start_feed ;
pid_filt - > demux - > stop_feed = pid_filt - > stop_feed ;
if ( ( ( - - ( temp_int - > internal - > filts_used ) ) < = 0 ) & &
( ( temp_int - > internal - > cis_used ) < = 0 ) ) {
ci_dbg_print ( " %s: Actually removing \n " , __func__ ) ;
remove_inode ( temp_int - > internal ) ;
kfree ( pid_filt - > internal ) ;
}
kfree ( pid_filt ) ;
}
}
EXPORT_SYMBOL ( altera_hw_filt_release ) ;
void altera_ci_release ( void * dev , int ci_nr )
{
struct fpga_inode * temp_int = find_inode ( dev ) ;
struct altera_ci_state * state = NULL ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( temp_int ! = NULL ) {
state = temp_int - > internal - > state [ ci_nr - 1 ] ;
altera_hw_filt_release ( dev , ci_nr ) ;
if ( ( ( temp_int - > internal - > filts_used ) < = 0 ) & &
( ( - - ( temp_int - > internal - > cis_used ) ) < = 0 ) ) {
ci_dbg_print ( " %s: Actually removing \n " , __func__ ) ;
remove_inode ( temp_int - > internal ) ;
kfree ( state - > internal ) ;
}
if ( state ! = NULL ) {
if ( state - > ca . data ! = NULL )
dvb_ca_en50221_release ( & state - > ca ) ;
kfree ( state ) ;
}
}
}
EXPORT_SYMBOL ( altera_ci_release ) ;
static void altera_pid_control ( struct netup_hw_pid_filter * pid_filt ,
u16 pid , int onoff )
{
struct fpga_internal * inter = pid_filt - > internal ;
u8 store = 0 ;
2011-01-25 17:08:00 -03:00
/* pid 0-0x1f always enabled, don't touch them */
if ( ( pid = = 0x2000 ) | | ( pid < 0x20 ) )
2011-01-25 17:01:00 -03:00
return ;
mutex_lock ( & inter - > fpga_mutex ) ;
netup_fpga_op_rw ( inter , NETUP_CI_PID_ADDR0 , ( pid > > 3 ) & 0xff , 0 ) ;
netup_fpga_op_rw ( inter , NETUP_CI_PID_ADDR1 ,
( ( pid > > 11 ) & 0x03 ) | ( pid_filt - > nr < < 2 ) , 0 ) ;
store = netup_fpga_op_rw ( inter , NETUP_CI_PID_DATA , 0 , NETUP_CI_FLG_RD ) ;
if ( onoff ) /* 0 - on, 1 - off */
store | = ( 1 < < ( pid & 7 ) ) ;
else
store & = ~ ( 1 < < ( pid & 7 ) ) ;
netup_fpga_op_rw ( inter , NETUP_CI_PID_DATA , store , 0 ) ;
mutex_unlock ( & inter - > fpga_mutex ) ;
pid_dbg_print ( " %s: (%d) set pid: %5d 0x%04x '%s' \n " , __func__ ,
pid_filt - > nr , pid , pid , onoff ? " off " : " on " ) ;
}
static void altera_toggle_fullts_streaming ( struct netup_hw_pid_filter * pid_filt ,
int filt_nr , int onoff )
{
struct fpga_internal * inter = pid_filt - > internal ;
u8 store = 0 ;
int i ;
pid_dbg_print ( " %s: pid_filt->nr[%d] now %s \n " , __func__ , pid_filt - > nr ,
onoff ? " off " : " on " ) ;
if ( onoff ) /* 0 - on, 1 - off */
store = 0xff ; /* ignore pid */
else
store = 0 ; /* enable pid */
mutex_lock ( & inter - > fpga_mutex ) ;
for ( i = 0 ; i < 1024 ; i + + ) {
netup_fpga_op_rw ( inter , NETUP_CI_PID_ADDR0 , i & 0xff , 0 ) ;
netup_fpga_op_rw ( inter , NETUP_CI_PID_ADDR1 ,
( ( i > > 8 ) & 0x03 ) | ( pid_filt - > nr < < 2 ) , 0 ) ;
2011-01-25 17:08:00 -03:00
/* pid 0-0x1f always enabled */
netup_fpga_op_rw ( inter , NETUP_CI_PID_DATA ,
( i > 3 ? store : 0 ) , 0 ) ;
2011-01-25 17:01:00 -03:00
}
mutex_unlock ( & inter - > fpga_mutex ) ;
}
int altera_pid_feed_control ( void * demux_dev , int filt_nr ,
struct dvb_demux_feed * feed , int onoff )
{
struct fpga_inode * temp_int = find_dinode ( demux_dev ) ;
struct fpga_internal * inter = temp_int - > internal ;
struct netup_hw_pid_filter * pid_filt = inter - > pid_filt [ filt_nr - 1 ] ;
altera_pid_control ( pid_filt , feed - > pid , onoff ? 0 : 1 ) ;
/* call old feed proc's */
if ( onoff )
pid_filt - > start_feed ( feed ) ;
else
pid_filt - > stop_feed ( feed ) ;
if ( feed - > pid = = 0x2000 )
altera_toggle_fullts_streaming ( pid_filt , filt_nr ,
onoff ? 0 : 1 ) ;
return 0 ;
}
EXPORT_SYMBOL ( altera_pid_feed_control ) ;
int altera_ci_start_feed ( struct dvb_demux_feed * feed , int num )
{
altera_pid_feed_control ( feed - > demux , num , feed , 1 ) ;
return 0 ;
}
int altera_ci_stop_feed ( struct dvb_demux_feed * feed , int num )
{
altera_pid_feed_control ( feed - > demux , num , feed , 0 ) ;
return 0 ;
}
int altera_ci_start_feed_1 ( struct dvb_demux_feed * feed )
{
return altera_ci_start_feed ( feed , 1 ) ;
}
int altera_ci_stop_feed_1 ( struct dvb_demux_feed * feed )
{
return altera_ci_stop_feed ( feed , 1 ) ;
}
int altera_ci_start_feed_2 ( struct dvb_demux_feed * feed )
{
return altera_ci_start_feed ( feed , 2 ) ;
}
int altera_ci_stop_feed_2 ( struct dvb_demux_feed * feed )
{
return altera_ci_stop_feed ( feed , 2 ) ;
}
int altera_hw_filt_init ( struct altera_ci_config * config , int hw_filt_nr )
{
struct netup_hw_pid_filter * pid_filt = NULL ;
struct fpga_inode * temp_int = find_inode ( config - > dev ) ;
struct fpga_internal * inter = NULL ;
int ret = 0 ;
pid_filt = kzalloc ( sizeof ( struct netup_hw_pid_filter ) , GFP_KERNEL ) ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( ! pid_filt ) {
ret = - ENOMEM ;
goto err ;
}
if ( temp_int ! = NULL ) {
inter = temp_int - > internal ;
( inter - > filts_used ) + + ;
ci_dbg_print ( " %s: Find Internal Structure! \n " , __func__ ) ;
} else {
inter = kzalloc ( sizeof ( struct fpga_internal ) , GFP_KERNEL ) ;
if ( ! inter ) {
ret = - ENOMEM ;
goto err ;
}
temp_int = append_internal ( inter ) ;
inter - > filts_used = 1 ;
inter - > dev = config - > dev ;
inter - > fpga_rw = config - > fpga_rw ;
mutex_init ( & inter - > fpga_mutex ) ;
inter - > strt_wrk = 1 ;
ci_dbg_print ( " %s: Create New Internal Structure! \n " , __func__ ) ;
}
2011-03-06 09:27:44 -03:00
ci_dbg_print ( " %s: setting hw pid filter = %p for ci = %d \n " , __func__ ,
pid_filt , hw_filt_nr - 1 ) ;
2011-01-25 17:01:00 -03:00
inter - > pid_filt [ hw_filt_nr - 1 ] = pid_filt ;
pid_filt - > demux = config - > demux ;
pid_filt - > internal = inter ;
pid_filt - > nr = hw_filt_nr - 1 ;
/* store old feed controls */
pid_filt - > start_feed = config - > demux - > start_feed ;
pid_filt - > stop_feed = config - > demux - > stop_feed ;
/* replace with new feed controls */
if ( hw_filt_nr = = 1 ) {
pid_filt - > demux - > start_feed = altera_ci_start_feed_1 ;
pid_filt - > demux - > stop_feed = altera_ci_stop_feed_1 ;
} else if ( hw_filt_nr = = 2 ) {
pid_filt - > demux - > start_feed = altera_ci_start_feed_2 ;
pid_filt - > demux - > stop_feed = altera_ci_stop_feed_2 ;
}
altera_toggle_fullts_streaming ( pid_filt , 0 , 1 ) ;
return 0 ;
err :
ci_dbg_print ( " %s: Can't init hardware filter: Error %d \n " ,
__func__ , ret ) ;
kfree ( pid_filt ) ;
return ret ;
}
EXPORT_SYMBOL ( altera_hw_filt_init ) ;
int altera_ci_init ( struct altera_ci_config * config , int ci_nr )
{
struct altera_ci_state * state ;
struct fpga_inode * temp_int = find_inode ( config - > dev ) ;
struct fpga_internal * inter = NULL ;
int ret = 0 ;
u8 store = 0 ;
state = kzalloc ( sizeof ( struct altera_ci_state ) , GFP_KERNEL ) ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( ! state ) {
ret = - ENOMEM ;
goto err ;
}
if ( temp_int ! = NULL ) {
inter = temp_int - > internal ;
( inter - > cis_used ) + + ;
ci_dbg_print ( " %s: Find Internal Structure! \n " , __func__ ) ;
} else {
inter = kzalloc ( sizeof ( struct fpga_internal ) , GFP_KERNEL ) ;
if ( ! inter ) {
ret = - ENOMEM ;
goto err ;
}
temp_int = append_internal ( inter ) ;
inter - > cis_used = 1 ;
inter - > dev = config - > dev ;
inter - > fpga_rw = config - > fpga_rw ;
mutex_init ( & inter - > fpga_mutex ) ;
inter - > strt_wrk = 1 ;
ci_dbg_print ( " %s: Create New Internal Structure! \n " , __func__ ) ;
}
2011-03-06 09:27:44 -03:00
ci_dbg_print ( " %s: setting state = %p for ci = %d \n " , __func__ ,
state , ci_nr - 1 ) ;
2011-01-25 17:01:00 -03:00
inter - > state [ ci_nr - 1 ] = state ;
state - > internal = inter ;
state - > nr = ci_nr - 1 ;
state - > ca . owner = THIS_MODULE ;
state - > ca . read_attribute_mem = altera_ci_read_attribute_mem ;
state - > ca . write_attribute_mem = altera_ci_write_attribute_mem ;
state - > ca . read_cam_control = altera_ci_read_cam_ctl ;
state - > ca . write_cam_control = altera_ci_write_cam_ctl ;
state - > ca . slot_reset = altera_ci_slot_reset ;
state - > ca . slot_shutdown = altera_ci_slot_shutdown ;
state - > ca . slot_ts_enable = altera_ci_slot_ts_ctl ;
state - > ca . poll_slot_status = altera_poll_ci_slot_status ;
state - > ca . data = state ;
ret = dvb_ca_en50221_init ( config - > adapter ,
& state - > ca ,
/* flags */ 0 ,
/* n_slots */ 1 ) ;
if ( 0 ! = ret )
goto err ;
altera_hw_filt_init ( config , ci_nr ) ;
if ( inter - > strt_wrk ) {
INIT_WORK ( & inter - > work , netup_read_ci_status ) ;
inter - > strt_wrk = 0 ;
}
ci_dbg_print ( " %s: CI initialized! \n " , __func__ ) ;
mutex_lock ( & inter - > fpga_mutex ) ;
/* Enable div */
netup_fpga_op_rw ( inter , NETUP_CI_TSA_DIV , 0x0 , 0 ) ;
netup_fpga_op_rw ( inter , NETUP_CI_TSB_DIV , 0x0 , 0 ) ;
/* enable TS out */
store = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL2 , 0 , NETUP_CI_FLG_RD ) ;
store | = ( 3 < < 4 ) ;
netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL2 , store , 0 ) ;
ret = netup_fpga_op_rw ( inter , NETUP_CI_REVISION , 0 , NETUP_CI_FLG_RD ) ;
/* enable irq */
netup_fpga_op_rw ( inter , NETUP_CI_INT_CTRL , 0x44 , 0 ) ;
mutex_unlock ( & inter - > fpga_mutex ) ;
ci_dbg_print ( " %s: NetUP CI Revision = 0x%x \n " , __func__ , ret ) ;
schedule_work ( & inter - > work ) ;
return 0 ;
err :
ci_dbg_print ( " %s: Cannot initialize CI: Error %d. \n " , __func__ , ret ) ;
kfree ( state ) ;
return ret ;
}
EXPORT_SYMBOL ( altera_ci_init ) ;
int altera_ci_tuner_reset ( void * dev , int ci_nr )
{
struct fpga_inode * temp_int = find_inode ( dev ) ;
struct fpga_internal * inter = NULL ;
u8 store ;
ci_dbg_print ( " %s \n " , __func__ ) ;
if ( temp_int = = NULL )
return - 1 ;
if ( temp_int - > internal = = NULL )
return - 1 ;
inter = temp_int - > internal ;
mutex_lock ( & inter - > fpga_mutex ) ;
store = netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL2 , 0 , NETUP_CI_FLG_RD ) ;
store & = ~ ( 4 < < ( 2 - ci_nr ) ) ;
netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL2 , store , 0 ) ;
msleep ( 100 ) ;
store | = ( 4 < < ( 2 - ci_nr ) ) ;
netup_fpga_op_rw ( inter , NETUP_CI_BUSCTRL2 , store , 0 ) ;
mutex_unlock ( & inter - > fpga_mutex ) ;
return 0 ;
}
EXPORT_SYMBOL ( altera_ci_tuner_reset ) ;