2005-04-17 02:20:36 +04:00
/*
* dmxdev . c - DVB demultiplexer device
*
2006-03-10 21:22:31 +03:00
* Copyright ( C ) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
2005-04-17 02:20:36 +04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation ; either version 2.1
* 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 Lesser General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*
*/
# include <linux/spinlock.h>
# include <linux/slab.h>
# include <linux/vmalloc.h>
# include <linux/module.h>
# include <linux/poll.h>
# include <linux/ioctl.h>
# include <linux/wait.h>
# include <asm/uaccess.h>
# include <asm/system.h>
# include "dmxdev.h"
static int debug ;
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Turn on/off debugging (default:off). " ) ;
# define dprintk if (debug) printk
2006-03-14 23:31:01 +03:00
static int dvb_dmxdev_buffer_write ( struct dvb_ringbuffer * buf ,
const u8 * src , size_t len )
2005-04-17 02:20:36 +04:00
{
2006-03-14 23:31:01 +03:00
ssize_t free ;
2005-04-17 02:20:36 +04:00
if ( ! len )
return 0 ;
if ( ! buf - > data )
return 0 ;
2006-03-14 23:31:01 +03:00
free = dvb_ringbuffer_free ( buf ) ;
if ( len > free ) {
2005-04-17 02:20:36 +04:00
dprintk ( " dmxdev: buffer overflow \n " ) ;
2006-03-14 23:31:01 +03:00
return - EOVERFLOW ;
2005-04-17 02:20:36 +04:00
}
2006-03-14 23:31:01 +03:00
return dvb_ringbuffer_write ( buf , src , len ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-14 23:31:01 +03:00
static ssize_t dvb_dmxdev_buffer_read ( struct dvb_ringbuffer * src ,
2006-03-10 21:22:31 +03:00
int non_blocking , char __user * buf ,
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2006-03-14 23:31:01 +03:00
size_t todo ;
ssize_t avail ;
ssize_t ret = 0 ;
2005-04-17 02:20:36 +04:00
if ( ! src - > data )
return 0 ;
2006-03-14 23:31:01 +03:00
if ( src - > error ) {
ret = src - > error ;
dvb_ringbuffer_flush ( src ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2006-03-14 23:31:01 +03:00
for ( todo = count ; todo > 0 ; todo - = ret ) {
if ( non_blocking & & dvb_ringbuffer_empty ( src ) ) {
ret = - EWOULDBLOCK ;
break ;
}
2005-04-17 02:20:36 +04:00
2006-03-14 23:31:01 +03:00
ret = wait_event_interruptible ( src - > queue ,
! dvb_ringbuffer_empty ( src ) | |
( src - > error ! = 0 ) ) ;
if ( ret < 0 )
break ;
2005-04-17 02:20:36 +04:00
2006-03-14 23:31:01 +03:00
if ( src - > error ) {
ret = src - > error ;
dvb_ringbuffer_flush ( src ) ;
break ;
2005-04-17 02:20:36 +04:00
}
2006-03-14 23:31:01 +03:00
avail = dvb_ringbuffer_avail ( src ) ;
2006-03-10 21:22:31 +03:00
if ( avail > todo )
avail = todo ;
2006-03-14 23:31:01 +03:00
2007-07-13 18:54:35 +04:00
ret = dvb_ringbuffer_read ( src , ( u8 * ) buf , avail , 1 ) ;
2006-03-14 23:31:01 +03:00
if ( ret < 0 )
break ;
buf + = ret ;
2005-04-17 02:20:36 +04:00
}
2006-03-14 23:31:01 +03:00
return ( count - todo ) ? ( count - todo ) : ret ;
2005-04-17 02:20:36 +04:00
}
2006-03-10 21:22:31 +03:00
static struct dmx_frontend * get_fe ( struct dmx_demux * demux , int type )
2005-04-17 02:20:36 +04:00
{
struct list_head * head , * pos ;
2006-03-10 21:22:31 +03:00
head = demux - > get_frontends ( demux ) ;
2005-04-17 02:20:36 +04:00
if ( ! head )
return NULL ;
list_for_each ( pos , head )
2006-03-10 21:22:31 +03:00
if ( DMX_FE_ENTRY ( pos ) - > source = = type )
2005-04-17 02:20:36 +04:00
return DMX_FE_ENTRY ( pos ) ;
return NULL ;
}
static int dvb_dvr_open ( struct inode * inode , struct file * file )
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
struct dmx_frontend * front ;
2006-03-10 21:22:31 +03:00
dprintk ( " function : %s \n " , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdev - > mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
2007-04-14 17:19:18 +04:00
if ( dmxdev - > exit ) {
mutex_unlock ( & dmxdev - > mutex ) ;
return - ENODEV ;
}
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDWR ) {
if ( ! ( dmxdev - > capabilities & DMXDEV_CAP_DUPLEX ) ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - EOPNOTSUPP ;
}
}
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
2006-03-30 22:53:32 +04:00
void * mem ;
if ( ! dvbdev - > readers ) {
mutex_unlock ( & dmxdev - > mutex ) ;
return - EBUSY ;
}
mem = vmalloc ( DVR_BUFFER_SIZE ) ;
2006-03-14 23:31:01 +03:00
if ( ! mem ) {
2006-03-10 21:22:31 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
return - ENOMEM ;
}
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_init ( & dmxdev - > dvr_buffer , mem , DVR_BUFFER_SIZE ) ;
2006-03-30 22:53:32 +04:00
dvbdev - > readers - - ;
2005-04-17 02:20:36 +04:00
}
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
dmxdev - > dvr_orig_fe = dmxdev - > demux - > frontend ;
2005-04-17 02:20:36 +04:00
if ( ! dmxdev - > demux - > write ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - EOPNOTSUPP ;
}
2006-03-10 21:22:31 +03:00
front = get_fe ( dmxdev - > demux , DMX_MEMORY_FE ) ;
2005-04-17 02:20:36 +04:00
if ( ! front ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
dmxdev - > demux - > disconnect_frontend ( dmxdev - > demux ) ;
dmxdev - > demux - > connect_frontend ( dmxdev - > demux , front ) ;
}
2007-04-14 17:19:18 +04:00
dvbdev - > users + + ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int dvb_dvr_release ( struct inode * inode , struct file * file )
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
2007-03-10 12:21:25 +03:00
mutex_lock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) = = O_WRONLY ) {
2005-04-17 02:20:36 +04:00
dmxdev - > demux - > disconnect_frontend ( dmxdev - > demux ) ;
dmxdev - > demux - > connect_frontend ( dmxdev - > demux ,
dmxdev - > dvr_orig_fe ) ;
}
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
2006-03-30 22:53:32 +04:00
dvbdev - > readers + + ;
2005-04-17 02:20:36 +04:00
if ( dmxdev - > dvr_buffer . data ) {
2006-03-10 21:22:31 +03:00
void * mem = dmxdev - > dvr_buffer . data ;
2005-04-17 02:20:36 +04:00
mb ( ) ;
spin_lock_irq ( & dmxdev - > lock ) ;
2006-03-10 21:22:31 +03:00
dmxdev - > dvr_buffer . data = NULL ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & dmxdev - > lock ) ;
vfree ( mem ) ;
}
}
2007-04-14 17:19:18 +04:00
/* TODO */
dvbdev - > users - - ;
if ( dvbdev - > users = = - 1 & & dmxdev - > exit = = 1 ) {
fops_put ( file - > f_op ) ;
file - > f_op = NULL ;
mutex_unlock ( & dmxdev - > mutex ) ;
wake_up ( & dvbdev - > wait_queue ) ;
} else
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static ssize_t dvb_dvr_write ( struct file * file , const char __user * buf ,
2006-03-10 21:22:31 +03:00
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
int ret ;
if ( ! dmxdev - > demux - > write )
return - EOPNOTSUPP ;
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) ! = O_WRONLY )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdev - > mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
2007-04-14 17:19:18 +04:00
if ( dmxdev - > exit ) {
mutex_unlock ( & dmxdev - > mutex ) ;
return - ENODEV ;
}
2006-03-10 21:22:31 +03:00
ret = dmxdev - > demux - > write ( dmxdev - > demux , buf , count ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static ssize_t dvb_dvr_read ( struct file * file , char __user * buf , size_t count ,
2006-03-10 21:22:31 +03:00
loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
int ret ;
2007-04-14 17:19:18 +04:00
if ( dmxdev - > exit ) {
mutex_unlock ( & dmxdev - > mutex ) ;
return - ENODEV ;
}
2006-02-07 11:49:14 +03:00
//mutex_lock(&dmxdev->mutex);
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_buffer_read ( & dmxdev - > dvr_buffer ,
file - > f_flags & O_NONBLOCK ,
buf , count , ppos ) ;
2006-02-07 11:49:14 +03:00
//mutex_unlock(&dmxdev->mutex);
2005-04-17 02:20:36 +04:00
return ret ;
}
2006-03-10 21:22:31 +03:00
static inline void dvb_dmxdev_filter_state_set ( struct dmxdev_filter
* dmxdevfilter , int state )
2005-04-17 02:20:36 +04:00
{
spin_lock_irq ( & dmxdevfilter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > state = state ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & dmxdevfilter - > dev - > lock ) ;
}
2006-03-10 21:22:31 +03:00
static int dvb_dmxdev_set_buffer_size ( struct dmxdev_filter * dmxdevfilter ,
unsigned long size )
2005-04-17 02:20:36 +04:00
{
2006-03-14 23:31:01 +03:00
struct dvb_ringbuffer * buf = & dmxdevfilter - > buffer ;
2005-04-17 02:20:36 +04:00
void * mem ;
2006-03-10 21:22:31 +03:00
if ( buf - > size = = size )
2005-04-17 02:20:36 +04:00
return 0 ;
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > state > = DMXDEV_STATE_GO )
2005-04-17 02:20:36 +04:00
return - EBUSY ;
spin_lock_irq ( & dmxdevfilter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
mem = buf - > data ;
buf - > data = NULL ;
buf - > size = size ;
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_flush ( buf ) ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & dmxdevfilter - > dev - > lock ) ;
vfree ( mem ) ;
if ( buf - > size ) {
2006-03-10 21:22:31 +03:00
mem = vmalloc ( dmxdevfilter - > buffer . size ) ;
2005-04-17 02:20:36 +04:00
if ( ! mem )
return - ENOMEM ;
spin_lock_irq ( & dmxdevfilter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
buf - > data = mem ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & dmxdevfilter - > dev - > lock ) ;
}
return 0 ;
}
static void dvb_dmxdev_filter_timeout ( unsigned long data )
{
2006-03-10 21:22:31 +03:00
struct dmxdev_filter * dmxdevfilter = ( struct dmxdev_filter * ) data ;
2005-04-17 02:20:36 +04:00
2006-03-10 21:22:31 +03:00
dmxdevfilter - > buffer . error = - ETIMEDOUT ;
2005-04-17 02:20:36 +04:00
spin_lock_irq ( & dmxdevfilter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > state = DMXDEV_STATE_TIMEDOUT ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & dmxdevfilter - > dev - > lock ) ;
wake_up ( & dmxdevfilter - > buffer . queue ) ;
}
static void dvb_dmxdev_filter_timer ( struct dmxdev_filter * dmxdevfilter )
{
2006-03-10 21:22:31 +03:00
struct dmx_sct_filter_params * para = & dmxdevfilter - > params . sec ;
2005-04-17 02:20:36 +04:00
del_timer ( & dmxdevfilter - > timer ) ;
if ( para - > timeout ) {
2006-03-10 21:22:31 +03:00
dmxdevfilter - > timer . function = dvb_dmxdev_filter_timeout ;
dmxdevfilter - > timer . data = ( unsigned long ) dmxdevfilter ;
dmxdevfilter - > timer . expires =
jiffies + 1 + ( HZ / 2 + HZ * para - > timeout ) / 1000 ;
2005-04-17 02:20:36 +04:00
add_timer ( & dmxdevfilter - > timer ) ;
}
}
static int dvb_dmxdev_section_callback ( const u8 * buffer1 , size_t buffer1_len ,
2006-03-10 21:22:31 +03:00
const u8 * buffer2 , size_t buffer2_len ,
struct dmx_section_filter * filter ,
enum dmx_success success )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:24 +04:00
struct dmxdev_filter * dmxdevfilter = filter - > priv ;
2005-04-17 02:20:36 +04:00
int ret ;
if ( dmxdevfilter - > buffer . error ) {
wake_up ( & dmxdevfilter - > buffer . queue ) ;
return 0 ;
}
spin_lock ( & dmxdevfilter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > state ! = DMXDEV_STATE_GO ) {
2005-04-17 02:20:36 +04:00
spin_unlock ( & dmxdevfilter - > dev - > lock ) ;
return 0 ;
}
del_timer ( & dmxdevfilter - > timer ) ;
dprintk ( " dmxdev: section callback %02x %02x %02x %02x %02x %02x \n " ,
buffer1 [ 0 ] , buffer1 [ 1 ] ,
2006-03-10 21:22:31 +03:00
buffer1 [ 2 ] , buffer1 [ 3 ] , buffer1 [ 4 ] , buffer1 [ 5 ] ) ;
ret = dvb_dmxdev_buffer_write ( & dmxdevfilter - > buffer , buffer1 ,
buffer1_len ) ;
if ( ret = = buffer1_len ) {
ret = dvb_dmxdev_buffer_write ( & dmxdevfilter - > buffer , buffer2 ,
buffer2_len ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-10 21:22:31 +03:00
if ( ret < 0 ) {
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_flush ( & dmxdevfilter - > buffer ) ;
dmxdevfilter - > buffer . error = ret ;
2005-04-17 02:20:36 +04:00
}
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > params . sec . flags & DMX_ONESHOT )
dmxdevfilter - > state = DMXDEV_STATE_DONE ;
2005-04-17 02:20:36 +04:00
spin_unlock ( & dmxdevfilter - > dev - > lock ) ;
wake_up ( & dmxdevfilter - > buffer . queue ) ;
return 0 ;
}
static int dvb_dmxdev_ts_callback ( const u8 * buffer1 , size_t buffer1_len ,
2006-03-10 21:22:31 +03:00
const u8 * buffer2 , size_t buffer2_len ,
struct dmx_ts_feed * feed ,
enum dmx_success success )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:24 +04:00
struct dmxdev_filter * dmxdevfilter = feed - > priv ;
2006-03-14 23:31:01 +03:00
struct dvb_ringbuffer * buffer ;
2005-04-17 02:20:36 +04:00
int ret ;
spin_lock ( & dmxdevfilter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > params . pes . output = = DMX_OUT_DECODER ) {
2005-04-17 02:20:36 +04:00
spin_unlock ( & dmxdevfilter - > dev - > lock ) ;
return 0 ;
}
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > params . pes . output = = DMX_OUT_TAP )
buffer = & dmxdevfilter - > buffer ;
2005-04-17 02:20:36 +04:00
else
2006-03-10 21:22:31 +03:00
buffer = & dmxdevfilter - > dev - > dvr_buffer ;
2005-04-17 02:20:36 +04:00
if ( buffer - > error ) {
spin_unlock ( & dmxdevfilter - > dev - > lock ) ;
wake_up ( & buffer - > queue ) ;
return 0 ;
}
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_buffer_write ( buffer , buffer1 , buffer1_len ) ;
if ( ret = = buffer1_len )
ret = dvb_dmxdev_buffer_write ( buffer , buffer2 , buffer2_len ) ;
if ( ret < 0 ) {
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_flush ( buffer ) ;
buffer - > error = ret ;
2005-04-17 02:20:36 +04:00
}
spin_unlock ( & dmxdevfilter - > dev - > lock ) ;
wake_up ( & buffer - > queue ) ;
return 0 ;
}
/* stop feed but only mark the specified filter as stopped (state set) */
static int dvb_dmxdev_feed_stop ( struct dmxdev_filter * dmxdevfilter )
{
dvb_dmxdev_filter_state_set ( dmxdevfilter , DMXDEV_STATE_SET ) ;
switch ( dmxdevfilter - > type ) {
case DMXDEV_TYPE_SEC :
del_timer ( & dmxdevfilter - > timer ) ;
dmxdevfilter - > feed . sec - > stop_filtering ( dmxdevfilter - > feed . sec ) ;
break ;
case DMXDEV_TYPE_PES :
dmxdevfilter - > feed . ts - > stop_filtering ( dmxdevfilter - > feed . ts ) ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
/* start feed associated with the specified filter */
static int dvb_dmxdev_feed_start ( struct dmxdev_filter * filter )
{
2006-03-10 21:22:31 +03:00
dvb_dmxdev_filter_state_set ( filter , DMXDEV_STATE_GO ) ;
2005-04-17 02:20:36 +04:00
switch ( filter - > type ) {
case DMXDEV_TYPE_SEC :
return filter - > feed . sec - > start_filtering ( filter - > feed . sec ) ;
case DMXDEV_TYPE_PES :
return filter - > feed . ts - > start_filtering ( filter - > feed . ts ) ;
default :
return - EINVAL ;
}
return 0 ;
}
/* restart section feed if it has filters left associated with it,
otherwise release the feed */
static int dvb_dmxdev_feed_restart ( struct dmxdev_filter * filter )
{
int i ;
struct dmxdev * dmxdev = filter - > dev ;
u16 pid = filter - > params . sec . pid ;
2006-03-10 21:22:31 +03:00
for ( i = 0 ; i < dmxdev - > filternum ; i + + )
if ( dmxdev - > filter [ i ] . state > = DMXDEV_STATE_GO & &
dmxdev - > filter [ i ] . type = = DMXDEV_TYPE_SEC & &
dmxdev - > filter [ i ] . params . sec . pid = = pid ) {
2005-04-17 02:20:36 +04:00
dvb_dmxdev_feed_start ( & dmxdev - > filter [ i ] ) ;
return 0 ;
}
2006-03-10 21:22:31 +03:00
filter - > dev - > demux - > release_section_feed ( dmxdev - > demux ,
filter - > feed . sec ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int dvb_dmxdev_filter_stop ( struct dmxdev_filter * dmxdevfilter )
{
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > state < DMXDEV_STATE_GO )
2005-04-17 02:20:36 +04:00
return 0 ;
switch ( dmxdevfilter - > type ) {
case DMXDEV_TYPE_SEC :
if ( ! dmxdevfilter - > feed . sec )
break ;
dvb_dmxdev_feed_stop ( dmxdevfilter ) ;
if ( dmxdevfilter - > filter . sec )
dmxdevfilter - > feed . sec - >
2006-03-10 21:22:31 +03:00
release_filter ( dmxdevfilter - > feed . sec ,
dmxdevfilter - > filter . sec ) ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_feed_restart ( dmxdevfilter ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > feed . sec = NULL ;
2005-04-17 02:20:36 +04:00
break ;
case DMXDEV_TYPE_PES :
if ( ! dmxdevfilter - > feed . ts )
break ;
dvb_dmxdev_feed_stop ( dmxdevfilter ) ;
dmxdevfilter - > dev - > demux - >
2006-03-10 21:22:31 +03:00
release_ts_feed ( dmxdevfilter - > dev - > demux ,
dmxdevfilter - > feed . ts ) ;
dmxdevfilter - > feed . ts = NULL ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > state = = DMXDEV_STATE_ALLOCATED )
2005-04-17 02:20:36 +04:00
return 0 ;
return - EINVAL ;
}
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_flush ( & dmxdevfilter - > buffer ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline int dvb_dmxdev_filter_reset ( struct dmxdev_filter * dmxdevfilter )
{
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > state < DMXDEV_STATE_SET )
2005-04-17 02:20:36 +04:00
return 0 ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > type = DMXDEV_TYPE_NONE ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_filter_state_set ( dmxdevfilter , DMXDEV_STATE_ALLOCATED ) ;
return 0 ;
}
static int dvb_dmxdev_filter_start ( struct dmxdev_filter * filter )
{
struct dmxdev * dmxdev = filter - > dev ;
void * mem ;
int ret , i ;
if ( filter - > state < DMXDEV_STATE_SET )
return - EINVAL ;
if ( filter - > state > = DMXDEV_STATE_GO )
dvb_dmxdev_filter_stop ( filter ) ;
2006-03-14 23:31:01 +03:00
if ( ! filter - > buffer . data ) {
2005-04-17 02:20:36 +04:00
mem = vmalloc ( filter - > buffer . size ) ;
2006-03-14 23:31:01 +03:00
if ( ! mem )
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
spin_lock_irq ( & filter - > dev - > lock ) ;
2006-03-10 21:22:31 +03:00
filter - > buffer . data = mem ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & filter - > dev - > lock ) ;
}
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_flush ( & filter - > buffer ) ;
2005-04-17 02:20:36 +04:00
switch ( filter - > type ) {
case DMXDEV_TYPE_SEC :
{
2006-03-10 21:22:31 +03:00
struct dmx_sct_filter_params * para = & filter - > params . sec ;
struct dmx_section_filter * * secfilter = & filter - > filter . sec ;
struct dmx_section_feed * * secfeed = & filter - > feed . sec ;
* secfilter = NULL ;
* secfeed = NULL ;
2005-04-17 02:20:36 +04:00
/* find active filter/feed with same PID */
2006-03-10 21:22:31 +03:00
for ( i = 0 ; i < dmxdev - > filternum ; i + + ) {
2005-04-17 02:20:36 +04:00
if ( dmxdev - > filter [ i ] . state > = DMXDEV_STATE_GO & &
2006-03-10 21:21:28 +03:00
dmxdev - > filter [ i ] . type = = DMXDEV_TYPE_SEC & &
dmxdev - > filter [ i ] . params . sec . pid = = para - > pid ) {
2005-04-17 02:20:36 +04:00
* secfeed = dmxdev - > filter [ i ] . feed . sec ;
break ;
}
}
/* if no feed found, try to allocate new one */
if ( ! * secfeed ) {
2006-03-10 21:22:31 +03:00
ret = dmxdev - > demux - > allocate_section_feed ( dmxdev - > demux ,
secfeed ,
dvb_dmxdev_section_callback ) ;
if ( ret < 0 ) {
printk ( " DVB (%s): could not alloc feed \n " ,
__FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
2006-03-10 21:22:31 +03:00
ret = ( * secfeed ) - > set ( * secfeed , para - > pid , 32768 ,
( para - > flags & DMX_CHECK_CRC ) ? 1 : 0 ) ;
if ( ret < 0 ) {
printk ( " DVB (%s): could not set feed \n " ,
__FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_feed_restart ( filter ) ;
return ret ;
}
} else {
dvb_dmxdev_feed_stop ( filter ) ;
}
2006-03-10 21:22:31 +03:00
ret = ( * secfeed ) - > allocate_filter ( * secfeed , secfilter ) ;
2005-04-17 02:20:36 +04:00
if ( ret < 0 ) {
dvb_dmxdev_feed_restart ( filter ) ;
filter - > feed . sec - > start_filtering ( * secfeed ) ;
2006-03-10 21:22:31 +03:00
dprintk ( " could not get filter \n " ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
( * secfilter ) - > priv = filter ;
memcpy ( & ( ( * secfilter ) - > filter_value [ 3 ] ) ,
2006-03-10 21:22:31 +03:00
& ( para - > filter . filter [ 1 ] ) , DMX_FILTER_SIZE - 1 ) ;
2005-04-17 02:20:36 +04:00
memcpy ( & ( * secfilter ) - > filter_mask [ 3 ] ,
2006-03-10 21:22:31 +03:00
& para - > filter . mask [ 1 ] , DMX_FILTER_SIZE - 1 ) ;
2005-04-17 02:20:36 +04:00
memcpy ( & ( * secfilter ) - > filter_mode [ 3 ] ,
2006-03-10 21:22:31 +03:00
& para - > filter . mode [ 1 ] , DMX_FILTER_SIZE - 1 ) ;
2005-04-17 02:20:36 +04:00
2006-03-10 21:22:31 +03:00
( * secfilter ) - > filter_value [ 0 ] = para - > filter . filter [ 0 ] ;
( * secfilter ) - > filter_mask [ 0 ] = para - > filter . mask [ 0 ] ;
( * secfilter ) - > filter_mode [ 0 ] = para - > filter . mode [ 0 ] ;
( * secfilter ) - > filter_mask [ 1 ] = 0 ;
( * secfilter ) - > filter_mask [ 2 ] = 0 ;
2005-04-17 02:20:36 +04:00
filter - > todo = 0 ;
2006-03-10 21:22:31 +03:00
ret = filter - > feed . sec - > start_filtering ( filter - > feed . sec ) ;
2005-04-17 02:20:36 +04:00
if ( ret < 0 )
return ret ;
dvb_dmxdev_filter_timer ( filter ) ;
break ;
}
case DMXDEV_TYPE_PES :
{
struct timespec timeout = { 0 } ;
struct dmx_pes_filter_params * para = & filter - > params . pes ;
dmx_output_t otype ;
int ret ;
int ts_type ;
enum dmx_ts_pes ts_pes ;
struct dmx_ts_feed * * tsfeed = & filter - > feed . ts ;
filter - > feed . ts = NULL ;
2006-03-10 21:22:31 +03:00
otype = para - > output ;
2005-04-17 02:20:36 +04:00
2006-03-10 21:22:31 +03:00
ts_pes = ( enum dmx_ts_pes ) para - > pes_type ;
2005-04-17 02:20:36 +04:00
2006-03-10 21:22:31 +03:00
if ( ts_pes < DMX_PES_OTHER )
ts_type = TS_DECODER ;
2005-04-17 02:20:36 +04:00
else
2006-03-10 21:22:31 +03:00
ts_type = 0 ;
2005-04-17 02:20:36 +04:00
if ( otype = = DMX_OUT_TS_TAP )
ts_type | = TS_PACKET ;
if ( otype = = DMX_OUT_TAP )
2006-03-10 21:22:31 +03:00
ts_type | = TS_PAYLOAD_ONLY | TS_PACKET ;
2005-04-17 02:20:36 +04:00
2006-03-10 21:22:31 +03:00
ret = dmxdev - > demux - > allocate_ts_feed ( dmxdev - > demux ,
tsfeed ,
dvb_dmxdev_ts_callback ) ;
if ( ret < 0 )
2005-04-17 02:20:36 +04:00
return ret ;
2006-03-10 21:22:31 +03:00
( * tsfeed ) - > priv = filter ;
2005-04-17 02:20:36 +04:00
ret = ( * tsfeed ) - > set ( * tsfeed , para - > pid , ts_type , ts_pes ,
2005-09-10 00:02:24 +04:00
32768 , timeout ) ;
2005-04-17 02:20:36 +04:00
if ( ret < 0 ) {
2006-03-10 21:22:31 +03:00
dmxdev - > demux - > release_ts_feed ( dmxdev - > demux ,
* tsfeed ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
ret = filter - > feed . ts - > start_filtering ( filter - > feed . ts ) ;
2005-07-08 04:57:38 +04:00
if ( ret < 0 ) {
2006-03-10 21:22:31 +03:00
dmxdev - > demux - > release_ts_feed ( dmxdev - > demux ,
* tsfeed ) ;
2005-04-17 02:20:36 +04:00
return ret ;
2005-07-08 04:57:38 +04:00
}
2005-04-17 02:20:36 +04:00
break ;
}
default :
return - EINVAL ;
}
dvb_dmxdev_filter_state_set ( filter , DMXDEV_STATE_GO ) ;
return 0 ;
}
static int dvb_demux_open ( struct inode * inode , struct file * file )
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
int i ;
struct dmxdev_filter * dmxdevfilter ;
if ( ! dmxdev - > filter )
return - EINVAL ;
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdev - > mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
2006-03-10 21:22:31 +03:00
for ( i = 0 ; i < dmxdev - > filternum ; i + + )
if ( dmxdev - > filter [ i ] . state = = DMXDEV_STATE_FREE )
2005-04-17 02:20:36 +04:00
break ;
2006-03-10 21:22:31 +03:00
if ( i = = dmxdev - > filternum ) {
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - EMFILE ;
}
2006-03-10 21:22:31 +03:00
dmxdevfilter = & dmxdev - > filter [ i ] ;
2006-02-07 11:49:14 +03:00
mutex_init ( & dmxdevfilter - > mutex ) ;
2006-03-10 21:22:31 +03:00
file - > private_data = dmxdevfilter ;
2005-04-17 02:20:36 +04:00
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_init ( & dmxdevfilter - > buffer , NULL , 8192 ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > type = DMXDEV_TYPE_NONE ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_filter_state_set ( dmxdevfilter , DMXDEV_STATE_ALLOCATED ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > feed . ts = NULL ;
2005-04-17 02:20:36 +04:00
init_timer ( & dmxdevfilter - > timer ) ;
2007-04-14 17:19:18 +04:00
dvbdev - > users + + ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-03-10 21:22:31 +03:00
static int dvb_dmxdev_filter_free ( struct dmxdev * dmxdev ,
struct dmxdev_filter * dmxdevfilter )
2005-04-17 02:20:36 +04:00
{
2007-03-10 12:21:25 +03:00
mutex_lock ( & dmxdev - > mutex ) ;
mutex_lock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_filter_stop ( dmxdevfilter ) ;
dvb_dmxdev_filter_reset ( dmxdevfilter ) ;
if ( dmxdevfilter - > buffer . data ) {
2006-03-10 21:22:31 +03:00
void * mem = dmxdevfilter - > buffer . data ;
2005-04-17 02:20:36 +04:00
spin_lock_irq ( & dmxdev - > lock ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > buffer . data = NULL ;
2005-04-17 02:20:36 +04:00
spin_unlock_irq ( & dmxdev - > lock ) ;
vfree ( mem ) ;
}
dvb_dmxdev_filter_state_set ( dmxdevfilter , DMXDEV_STATE_FREE ) ;
wake_up ( & dmxdevfilter - > buffer . queue ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline void invert_mode ( dmx_filter_t * filter )
{
int i ;
2006-03-10 21:22:31 +03:00
for ( i = 0 ; i < DMX_FILTER_SIZE ; i + + )
filter - > mode [ i ] ^ = 0xff ;
2005-04-17 02:20:36 +04:00
}
static int dvb_dmxdev_filter_set ( struct dmxdev * dmxdev ,
2006-03-10 21:22:31 +03:00
struct dmxdev_filter * dmxdevfilter ,
struct dmx_sct_filter_params * params )
2005-04-17 02:20:36 +04:00
{
2006-03-10 21:22:31 +03:00
dprintk ( " function : %s \n " , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_filter_stop ( dmxdevfilter ) ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > type = DMXDEV_TYPE_SEC ;
2005-04-17 02:20:36 +04:00
memcpy ( & dmxdevfilter - > params . sec ,
params , sizeof ( struct dmx_sct_filter_params ) ) ;
invert_mode ( & dmxdevfilter - > params . sec . filter ) ;
dvb_dmxdev_filter_state_set ( dmxdevfilter , DMXDEV_STATE_SET ) ;
2006-03-10 21:22:31 +03:00
if ( params - > flags & DMX_IMMEDIATE_START )
2005-04-17 02:20:36 +04:00
return dvb_dmxdev_filter_start ( dmxdevfilter ) ;
return 0 ;
}
static int dvb_dmxdev_pes_filter_set ( struct dmxdev * dmxdev ,
2006-03-10 21:22:31 +03:00
struct dmxdev_filter * dmxdevfilter ,
struct dmx_pes_filter_params * params )
2005-04-17 02:20:36 +04:00
{
dvb_dmxdev_filter_stop ( dmxdevfilter ) ;
2006-03-10 21:22:31 +03:00
if ( params - > pes_type > DMX_PES_OTHER | | params - > pes_type < 0 )
2005-04-17 02:20:36 +04:00
return - EINVAL ;
2006-03-10 21:22:31 +03:00
dmxdevfilter - > type = DMXDEV_TYPE_PES ;
memcpy ( & dmxdevfilter - > params , params ,
sizeof ( struct dmx_pes_filter_params ) ) ;
2005-04-17 02:20:36 +04:00
dvb_dmxdev_filter_state_set ( dmxdevfilter , DMXDEV_STATE_SET ) ;
2006-03-10 21:22:31 +03:00
if ( params - > flags & DMX_IMMEDIATE_START )
2005-04-17 02:20:36 +04:00
return dvb_dmxdev_filter_start ( dmxdevfilter ) ;
return 0 ;
}
static ssize_t dvb_dmxdev_read_sec ( struct dmxdev_filter * dfil ,
2006-03-10 21:22:31 +03:00
struct file * file , char __user * buf ,
size_t count , loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
int result , hcount ;
2006-03-10 21:22:31 +03:00
int done = 0 ;
if ( dfil - > todo < = 0 ) {
hcount = 3 + dfil - > todo ;
if ( hcount > count )
hcount = count ;
result = dvb_dmxdev_buffer_read ( & dfil - > buffer ,
file - > f_flags & O_NONBLOCK ,
buf , hcount , ppos ) ;
if ( result < 0 ) {
dfil - > todo = 0 ;
2005-04-17 02:20:36 +04:00
return result ;
}
2006-03-10 21:22:31 +03:00
if ( copy_from_user ( dfil - > secheader - dfil - > todo , buf , result ) )
2005-04-17 02:20:36 +04:00
return - EFAULT ;
2006-03-10 21:22:31 +03:00
buf + = result ;
done = result ;
count - = result ;
dfil - > todo - = result ;
if ( dfil - > todo > - 3 )
2005-04-17 02:20:36 +04:00
return done ;
2006-03-10 21:22:31 +03:00
dfil - > todo = ( ( dfil - > secheader [ 1 ] < < 8 ) | dfil - > secheader [ 2 ] ) & 0xfff ;
2005-04-17 02:20:36 +04:00
if ( ! count )
return done ;
}
2006-03-10 21:22:31 +03:00
if ( count > dfil - > todo )
count = dfil - > todo ;
result = dvb_dmxdev_buffer_read ( & dfil - > buffer ,
file - > f_flags & O_NONBLOCK ,
buf , count , ppos ) ;
if ( result < 0 )
2005-04-17 02:20:36 +04:00
return result ;
2006-03-10 21:22:31 +03:00
dfil - > todo - = result ;
return ( result + done ) ;
2005-04-17 02:20:36 +04:00
}
static ssize_t
2006-03-10 21:22:31 +03:00
dvb_demux_read ( struct file * file , char __user * buf , size_t count ,
loff_t * ppos )
2005-04-17 02:20:36 +04:00
{
2006-03-10 21:22:31 +03:00
struct dmxdev_filter * dmxdevfilter = file - > private_data ;
int ret ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdevfilter - > mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > type = = DMXDEV_TYPE_SEC )
ret = dvb_dmxdev_read_sec ( dmxdevfilter , file , buf , count , ppos ) ;
2005-04-17 02:20:36 +04:00
else
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_buffer_read ( & dmxdevfilter - > buffer ,
file - > f_flags & O_NONBLOCK ,
buf , count , ppos ) ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static int dvb_demux_do_ioctl ( struct inode * inode , struct file * file ,
unsigned int cmd , void * parg )
{
2005-07-08 04:57:39 +04:00
struct dmxdev_filter * dmxdevfilter = file - > private_data ;
2006-03-10 21:22:31 +03:00
struct dmxdev * dmxdev = dmxdevfilter - > dev ;
unsigned long arg = ( unsigned long ) parg ;
int ret = 0 ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdev - > mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
switch ( cmd ) {
case DMX_START :
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdevfilter - > mutex ) ) {
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
}
2006-03-10 21:22:31 +03:00
if ( dmxdevfilter - > state < DMXDEV_STATE_SET )
2005-04-17 02:20:36 +04:00
ret = - EINVAL ;
else
ret = dvb_dmxdev_filter_start ( dmxdevfilter ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
break ;
case DMX_STOP :
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdevfilter - > mutex ) ) {
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
}
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_filter_stop ( dmxdevfilter ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
break ;
case DMX_SET_FILTER :
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdevfilter - > mutex ) ) {
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
}
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_filter_set ( dmxdev , dmxdevfilter , parg ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
break ;
case DMX_SET_PES_FILTER :
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdevfilter - > mutex ) ) {
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
}
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_pes_filter_set ( dmxdev , dmxdevfilter , parg ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
break ;
case DMX_SET_BUFFER_SIZE :
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdevfilter - > mutex ) ) {
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
}
2006-03-10 21:22:31 +03:00
ret = dvb_dmxdev_set_buffer_size ( dmxdevfilter , arg ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdevfilter - > mutex ) ;
2005-04-17 02:20:36 +04:00
break ;
case DMX_GET_PES_PIDS :
if ( ! dmxdev - > demux - > get_pes_pids ) {
2006-03-10 21:22:31 +03:00
ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
break ;
}
2006-03-10 21:22:31 +03:00
dmxdev - > demux - > get_pes_pids ( dmxdev - > demux , parg ) ;
2005-04-17 02:20:36 +04:00
break ;
2005-09-10 00:02:21 +04:00
case DMX_GET_CAPS :
if ( ! dmxdev - > demux - > get_caps ) {
ret = - EINVAL ;
break ;
}
ret = dmxdev - > demux - > get_caps ( dmxdev - > demux , parg ) ;
break ;
case DMX_SET_SOURCE :
if ( ! dmxdev - > demux - > set_source ) {
ret = - EINVAL ;
break ;
}
ret = dmxdev - > demux - > set_source ( dmxdev - > demux , parg ) ;
break ;
2005-04-17 02:20:36 +04:00
case DMX_GET_STC :
if ( ! dmxdev - > demux - > get_stc ) {
2006-03-10 21:22:31 +03:00
ret = - EINVAL ;
2005-04-17 02:20:36 +04:00
break ;
}
ret = dmxdev - > demux - > get_stc ( dmxdev - > demux ,
2006-03-10 21:22:31 +03:00
( ( struct dmx_stc * ) parg ) - > num ,
& ( ( struct dmx_stc * ) parg ) - > stc ,
& ( ( struct dmx_stc * ) parg ) - > base ) ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-03-10 21:22:31 +03:00
ret = - EINVAL ;
break ;
2005-04-17 02:20:36 +04:00
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static int dvb_demux_ioctl ( struct inode * inode , struct file * file ,
unsigned int cmd , unsigned long arg )
{
return dvb_usercopy ( inode , file , cmd , arg , dvb_demux_do_ioctl ) ;
}
2006-03-10 21:22:31 +03:00
static unsigned int dvb_demux_poll ( struct file * file , poll_table * wait )
2005-04-17 02:20:36 +04:00
{
2005-07-08 04:57:39 +04:00
struct dmxdev_filter * dmxdevfilter = file - > private_data ;
2005-04-17 02:20:36 +04:00
unsigned int mask = 0 ;
if ( ! dmxdevfilter )
return - EINVAL ;
poll_wait ( file , & dmxdevfilter - > buffer . queue , wait ) ;
if ( dmxdevfilter - > state ! = DMXDEV_STATE_GO & &
dmxdevfilter - > state ! = DMXDEV_STATE_DONE & &
dmxdevfilter - > state ! = DMXDEV_STATE_TIMEDOUT )
return 0 ;
if ( dmxdevfilter - > buffer . error )
mask | = ( POLLIN | POLLRDNORM | POLLPRI | POLLERR ) ;
2006-03-14 23:31:01 +03:00
if ( ! dvb_ringbuffer_empty ( & dmxdevfilter - > buffer ) )
2005-04-17 02:20:36 +04:00
mask | = ( POLLIN | POLLRDNORM | POLLPRI ) ;
return mask ;
}
static int dvb_demux_release ( struct inode * inode , struct file * file )
{
2005-07-08 04:57:39 +04:00
struct dmxdev_filter * dmxdevfilter = file - > private_data ;
2005-04-17 02:20:36 +04:00
struct dmxdev * dmxdev = dmxdevfilter - > dev ;
2007-04-14 17:19:18 +04:00
int ret ;
ret = dvb_dmxdev_filter_free ( dmxdev , dmxdevfilter ) ;
mutex_lock ( & dmxdev - > mutex ) ;
dmxdev - > dvbdev - > users - - ;
if ( dmxdev - > dvbdev - > users = = 1 & & dmxdev - > exit = = 1 ) {
fops_put ( file - > f_op ) ;
file - > f_op = NULL ;
mutex_unlock ( & dmxdev - > mutex ) ;
wake_up ( & dmxdev - > dvbdev - > wait_queue ) ;
} else
mutex_unlock ( & dmxdev - > mutex ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
static struct file_operations dvb_demux_fops = {
2006-03-10 21:22:31 +03:00
. owner = THIS_MODULE ,
. read = dvb_demux_read ,
. ioctl = dvb_demux_ioctl ,
. open = dvb_demux_open ,
. release = dvb_demux_release ,
. poll = dvb_demux_poll ,
2005-04-17 02:20:36 +04:00
} ;
static struct dvb_device dvbdev_demux = {
2006-03-10 21:22:31 +03:00
. priv = NULL ,
. users = 1 ,
. writers = 1 ,
. fops = & dvb_demux_fops
2005-04-17 02:20:36 +04:00
} ;
static int dvb_dvr_do_ioctl ( struct inode * inode , struct file * file ,
2006-03-10 21:22:31 +03:00
unsigned int cmd , void * parg )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2006-03-10 21:22:31 +03:00
int ret ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & dmxdev - > mutex ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
switch ( cmd ) {
case DMX_SET_BUFFER_SIZE :
// FIXME: implement
2006-03-10 21:22:31 +03:00
ret = 0 ;
2005-04-17 02:20:36 +04:00
break ;
default :
2006-03-10 21:22:31 +03:00
ret = - EINVAL ;
break ;
2005-04-17 02:20:36 +04:00
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
return ret ;
}
static int dvb_dvr_ioctl ( struct inode * inode , struct file * file ,
2006-03-10 21:22:31 +03:00
unsigned int cmd , unsigned long arg )
2005-04-17 02:20:36 +04:00
{
return dvb_usercopy ( inode , file , cmd , arg , dvb_dvr_do_ioctl ) ;
}
2006-03-10 21:22:31 +03:00
static unsigned int dvb_dvr_poll ( struct file * file , poll_table * wait )
2005-04-17 02:20:36 +04:00
{
2005-05-17 08:54:24 +04:00
struct dvb_device * dvbdev = file - > private_data ;
struct dmxdev * dmxdev = dvbdev - > priv ;
2005-04-17 02:20:36 +04:00
unsigned int mask = 0 ;
2006-03-10 21:22:31 +03:00
dprintk ( " function : %s \n " , __FUNCTION__ ) ;
2005-04-17 02:20:36 +04:00
poll_wait ( file , & dmxdev - > dvr_buffer . queue , wait ) ;
2006-03-10 21:22:31 +03:00
if ( ( file - > f_flags & O_ACCMODE ) = = O_RDONLY ) {
2005-04-17 02:20:36 +04:00
if ( dmxdev - > dvr_buffer . error )
mask | = ( POLLIN | POLLRDNORM | POLLPRI | POLLERR ) ;
2006-03-14 23:31:01 +03:00
if ( ! dvb_ringbuffer_empty ( & dmxdev - > dvr_buffer ) )
2005-04-17 02:20:36 +04:00
mask | = ( POLLIN | POLLRDNORM | POLLPRI ) ;
} else
mask | = ( POLLOUT | POLLWRNORM | POLLPRI ) ;
return mask ;
}
static struct file_operations dvb_dvr_fops = {
2006-03-10 21:22:31 +03:00
. owner = THIS_MODULE ,
. read = dvb_dvr_read ,
. write = dvb_dvr_write ,
. ioctl = dvb_dvr_ioctl ,
. open = dvb_dvr_open ,
. release = dvb_dvr_release ,
. poll = dvb_dvr_poll ,
2005-04-17 02:20:36 +04:00
} ;
static struct dvb_device dvbdev_dvr = {
2006-03-10 21:22:31 +03:00
. priv = NULL ,
2006-03-30 22:53:32 +04:00
. readers = 1 ,
2007-04-14 17:19:18 +04:00
. users = 1 ,
2006-03-10 21:22:31 +03:00
. fops = & dvb_dvr_fops
2005-04-17 02:20:36 +04:00
} ;
2006-03-10 21:22:31 +03:00
int dvb_dmxdev_init ( struct dmxdev * dmxdev , struct dvb_adapter * dvb_adapter )
2005-04-17 02:20:36 +04:00
{
int i ;
if ( dmxdev - > demux - > open ( dmxdev - > demux ) < 0 )
return - EUSERS ;
2006-03-10 21:22:31 +03:00
dmxdev - > filter = vmalloc ( dmxdev - > filternum * sizeof ( struct dmxdev_filter ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! dmxdev - > filter )
return - ENOMEM ;
2006-02-07 11:49:14 +03:00
mutex_init ( & dmxdev - > mutex ) ;
2005-04-17 02:20:36 +04:00
spin_lock_init ( & dmxdev - > lock ) ;
2006-03-10 21:22:31 +03:00
for ( i = 0 ; i < dmxdev - > filternum ; i + + ) {
dmxdev - > filter [ i ] . dev = dmxdev ;
dmxdev - > filter [ i ] . buffer . data = NULL ;
dvb_dmxdev_filter_state_set ( & dmxdev - > filter [ i ] ,
DMXDEV_STATE_FREE ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-10 21:22:31 +03:00
dvb_register_device ( dvb_adapter , & dmxdev - > dvbdev , & dvbdev_demux , dmxdev ,
DVB_DEVICE_DEMUX ) ;
dvb_register_device ( dvb_adapter , & dmxdev - > dvr_dvbdev , & dvbdev_dvr ,
dmxdev , DVB_DEVICE_DVR ) ;
2005-04-17 02:20:36 +04:00
2006-03-14 23:31:01 +03:00
dvb_ringbuffer_init ( & dmxdev - > dvr_buffer , NULL , 8192 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-03-10 21:22:31 +03:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( dvb_dmxdev_init ) ;
2006-03-10 21:22:31 +03:00
void dvb_dmxdev_release ( struct dmxdev * dmxdev )
2005-04-17 02:20:36 +04:00
{
2007-04-14 17:19:18 +04:00
dmxdev - > exit = 1 ;
if ( dmxdev - > dvbdev - > users > 1 ) {
wait_event ( dmxdev - > dvbdev - > wait_queue ,
dmxdev - > dvbdev - > users = = 1 ) ;
}
if ( dmxdev - > dvr_dvbdev - > users > 1 ) {
wait_event ( dmxdev - > dvr_dvbdev - > wait_queue ,
dmxdev - > dvr_dvbdev - > users = = 1 ) ;
}
2005-04-17 02:20:36 +04:00
dvb_unregister_device ( dmxdev - > dvbdev ) ;
dvb_unregister_device ( dmxdev - > dvr_dvbdev ) ;
vfree ( dmxdev - > filter ) ;
2006-03-10 21:22:31 +03:00
dmxdev - > filter = NULL ;
2005-04-17 02:20:36 +04:00
dmxdev - > demux - > close ( dmxdev - > demux ) ;
}
2006-03-10 21:22:31 +03:00
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( dvb_dmxdev_release ) ;