2011-08-22 02:56:44 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <media/saa7146_vv.h>
/****************************************************************************/
/* resource management functions, shamelessly stolen from saa7134 driver */
int saa7146_res_get ( struct saa7146_fh * fh , unsigned int bit )
{
struct saa7146_dev * dev = fh - > dev ;
struct saa7146_vv * vv = dev - > vv_data ;
if ( fh - > resources & bit ) {
2011-08-22 02:56:44 +04:00
DEB_D ( " already allocated! want: 0x%02x, cur:0x%02x \n " ,
bit , vv - > resources ) ;
2005-04-17 02:20:36 +04:00
/* have it already allocated */
return 1 ;
}
/* is it free? */
if ( vv - > resources & bit ) {
2011-08-22 02:56:44 +04:00
DEB_D ( " locked! vv->resources:0x%02x, we want:0x%02x \n " ,
vv - > resources , bit ) ;
2005-04-17 02:20:36 +04:00
/* no, someone else uses it */
return 0 ;
}
/* it's free, grab it */
2011-08-22 02:56:44 +04:00
fh - > resources | = bit ;
2005-04-17 02:20:36 +04:00
vv - > resources | = bit ;
2011-08-22 02:56:44 +04:00
DEB_D ( " res: get 0x%02x, cur:0x%02x \n " , bit , vv - > resources ) ;
2005-04-17 02:20:36 +04:00
return 1 ;
}
void saa7146_res_free ( struct saa7146_fh * fh , unsigned int bits )
{
struct saa7146_dev * dev = fh - > dev ;
struct saa7146_vv * vv = dev - > vv_data ;
2006-03-13 19:17:11 +03:00
BUG_ON ( ( fh - > resources & bits ) ! = bits ) ;
2005-04-17 02:20:36 +04:00
2011-08-22 02:56:44 +04:00
fh - > resources & = ~ bits ;
2005-04-17 02:20:36 +04:00
vv - > resources & = ~ bits ;
2011-08-22 02:56:44 +04:00
DEB_D ( " res: put 0x%02x, cur:0x%02x \n " , bits , vv - > resources ) ;
2005-04-17 02:20:36 +04:00
}
/********************************************************************************/
/* common dma functions */
2006-03-10 18:29:15 +03:00
void saa7146_dma_free ( struct saa7146_dev * dev , struct videobuf_queue * q ,
struct saa7146_buf * buf )
2005-04-17 02:20:36 +04:00
{
2007-08-23 23:37:49 +04:00
struct videobuf_dmabuf * dma = videobuf_to_dma ( & buf - > vb ) ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p, buf:%p \n " , dev , buf ) ;
2005-04-17 02:20:36 +04:00
2006-03-13 19:17:11 +03:00
BUG_ON ( in_interrupt ( ) ) ;
2005-04-17 02:20:36 +04:00
2010-09-26 16:01:26 +04:00
videobuf_waiton ( q , & buf - > vb , 0 , 0 ) ;
2010-05-11 17:36:30 +04:00
videobuf_dma_unmap ( q - > dev , dma ) ;
2007-08-23 23:37:49 +04:00
videobuf_dma_free ( dma ) ;
2007-11-07 02:02:36 +03:00
buf - > vb . state = VIDEOBUF_NEEDS_INIT ;
2005-04-17 02:20:36 +04:00
}
/********************************************************************************/
/* common buffer functions */
int saa7146_buffer_queue ( struct saa7146_dev * dev ,
struct saa7146_dmaqueue * q ,
struct saa7146_buf * buf )
{
assert_spin_locked ( & dev - > slock ) ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p, dmaq:%p, buf:%p \n " , dev , q , buf ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( ! q ) ;
if ( NULL = = q - > curr ) {
q - > curr = buf ;
2011-08-22 02:56:44 +04:00
DEB_D ( " immediately activating buffer %p \n " , buf ) ;
2005-04-17 02:20:36 +04:00
buf - > activate ( dev , buf , NULL ) ;
} else {
list_add_tail ( & buf - > vb . queue , & q - > queue ) ;
2007-11-07 02:02:36 +03:00
buf - > vb . state = VIDEOBUF_QUEUED ;
2011-08-22 02:56:44 +04:00
DEB_D ( " adding buffer %p to queue. (active buffer present) \n " ,
buf ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
void saa7146_buffer_finish ( struct saa7146_dev * dev ,
struct saa7146_dmaqueue * q ,
int state )
{
assert_spin_locked ( & dev - > slock ) ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p, dmaq:%p, state:%d \n " , dev , q , state ) ;
DEB_EE ( " q->curr:%p \n " , q - > curr ) ;
2005-04-17 02:20:36 +04:00
BUG_ON ( ! q - > curr ) ;
/* finish current buffer */
if ( NULL = = q - > curr ) {
2011-08-22 02:56:44 +04:00
DEB_D ( " aiii. no current buffer \n " ) ;
2005-12-12 11:37:27 +03:00
return ;
2005-04-17 02:20:36 +04:00
}
2005-12-12 11:37:27 +03:00
2005-04-17 02:20:36 +04:00
q - > curr - > vb . state = state ;
do_gettimeofday ( & q - > curr - > vb . ts ) ;
wake_up ( & q - > curr - > vb . done ) ;
q - > curr = NULL ;
}
void saa7146_buffer_next ( struct saa7146_dev * dev ,
struct saa7146_dmaqueue * q , int vbi )
{
struct saa7146_buf * buf , * next = NULL ;
BUG_ON ( ! q ) ;
2011-08-22 02:56:44 +04:00
DEB_INT ( " dev:%p, dmaq:%p, vbi:%d \n " , dev , q , vbi ) ;
2005-04-17 02:20:36 +04:00
assert_spin_locked ( & dev - > slock ) ;
if ( ! list_empty ( & q - > queue ) ) {
/* activate next one from queue */
buf = list_entry ( q - > queue . next , struct saa7146_buf , vb . queue ) ;
list_del ( & buf - > vb . queue ) ;
if ( ! list_empty ( & q - > queue ) )
next = list_entry ( q - > queue . next , struct saa7146_buf , vb . queue ) ;
q - > curr = buf ;
2011-08-22 02:56:44 +04:00
DEB_INT ( " next buffer: buf:%p, prev:%p, next:%p \n " ,
buf , q - > queue . prev , q - > queue . next ) ;
2005-04-17 02:20:36 +04:00
buf - > activate ( dev , buf , next ) ;
} else {
2011-08-22 02:56:44 +04:00
DEB_INT ( " no next buffer. stopping. \n " ) ;
2005-04-17 02:20:36 +04:00
if ( 0 ! = vbi ) {
/* turn off video-dma3 */
saa7146_write ( dev , MC1 , MASK_20 ) ;
} else {
/* nothing to do -- just prevent next video-dma1 transfer
by lowering the protection address */
// fixme: fix this for vflip != 0
saa7146_write ( dev , PROT_ADDR1 , 0 ) ;
2005-12-12 11:37:27 +03:00
saa7146_write ( dev , MC2 , ( MASK_02 | MASK_18 ) ) ;
2005-04-17 02:20:36 +04:00
/* write the address of the rps-program */
saa7146_write ( dev , RPS_ADDR0 , dev - > d_rps0 . dma_handle ) ;
/* turn on rps */
saa7146_write ( dev , MC1 , ( MASK_12 | MASK_28 ) ) ;
2005-12-12 11:37:27 +03:00
2005-04-17 02:20:36 +04:00
/*
printk ( " vdma%d.base_even: 0x%08x \n " , 1 , saa7146_read ( dev , BASE_EVEN1 ) ) ;
printk ( " vdma%d.base_odd: 0x%08x \n " , 1 , saa7146_read ( dev , BASE_ODD1 ) ) ;
printk ( " vdma%d.prot_addr: 0x%08x \n " , 1 , saa7146_read ( dev , PROT_ADDR1 ) ) ;
printk ( " vdma%d.base_page: 0x%08x \n " , 1 , saa7146_read ( dev , BASE_PAGE1 ) ) ;
printk ( " vdma%d.pitch: 0x%08x \n " , 1 , saa7146_read ( dev , PITCH1 ) ) ;
printk ( " vdma%d.num_line_byte: 0x%08x \n " , 1 , saa7146_read ( dev , NUM_LINE_BYTE1 ) ) ;
*/
}
del_timer ( & q - > timeout ) ;
}
}
void saa7146_buffer_timeout ( unsigned long data )
{
struct saa7146_dmaqueue * q = ( struct saa7146_dmaqueue * ) data ;
struct saa7146_dev * dev = q - > dev ;
unsigned long flags ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p, dmaq:%p \n " , dev , q ) ;
2005-04-17 02:20:36 +04:00
spin_lock_irqsave ( & dev - > slock , flags ) ;
if ( q - > curr ) {
2011-08-22 02:56:44 +04:00
DEB_D ( " timeout on %p \n " , q - > curr ) ;
2007-11-07 02:02:36 +03:00
saa7146_buffer_finish ( dev , q , VIDEOBUF_ERROR ) ;
2005-04-17 02:20:36 +04:00
}
/* we don't restart the transfer here like other drivers do. when
a streaming capture is disabled , the timeout function will be
called for the current buffer . if we activate the next buffer now ,
we mess up our capture logic . if a timeout occurs on another buffer ,
then something is seriously broken before , so no need to buffer the
next capture IMHO . . . */
/*
saa7146_buffer_next ( dev , q ) ;
*/
spin_unlock_irqrestore ( & dev - > slock , flags ) ;
}
/********************************************************************************/
/* file operations */
2008-12-30 12:58:20 +03:00
static int fops_open ( struct file * file )
2005-04-17 02:20:36 +04:00
{
2009-12-10 16:44:04 +03:00
struct video_device * vdev = video_devdata ( file ) ;
struct saa7146_dev * dev = video_drvdata ( file ) ;
2005-04-17 02:20:36 +04:00
struct saa7146_fh * fh = NULL ;
int result = 0 ;
2009-12-10 16:44:04 +03:00
enum v4l2_buf_type type ;
2005-04-17 02:20:36 +04:00
2011-08-22 02:56:44 +04:00
DEB_EE ( " file:%p, dev:%s \n " , file , video_device_node_name ( vdev ) ) ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & saa7146_devices_lock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
2011-08-22 02:56:44 +04:00
DEB_D ( " using: %p \n " , dev ) ;
2005-04-17 02:20:36 +04:00
2009-12-10 16:44:04 +03:00
type = vdev - > vfl_type = = VFL_TYPE_GRABBER
? V4L2_BUF_TYPE_VIDEO_CAPTURE
: V4L2_BUF_TYPE_VBI_CAPTURE ;
2005-04-17 02:20:36 +04:00
/* check if an extension is registered */
if ( NULL = = dev - > ext ) {
2011-08-22 02:56:44 +04:00
DEB_S ( " no extension registered for this device \n " ) ;
2005-04-17 02:20:36 +04:00
result = - ENODEV ;
goto out ;
}
/* allocate per open data */
2006-01-12 00:40:56 +03:00
fh = kzalloc ( sizeof ( * fh ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( NULL = = fh ) {
2011-08-22 02:56:44 +04:00
DEB_S ( " cannot allocate memory for per open data \n " ) ;
2005-04-17 02:20:36 +04:00
result = - ENOMEM ;
goto out ;
}
2005-12-12 11:37:27 +03:00
2005-04-17 02:20:36 +04:00
file - > private_data = fh ;
fh - > dev = dev ;
fh - > type = type ;
if ( fh - > type = = V4L2_BUF_TYPE_VBI_CAPTURE ) {
2011-08-22 02:56:44 +04:00
DEB_S ( " initializing vbi... \n " ) ;
2006-01-09 23:21:37 +03:00
if ( dev - > ext_vv_data - > capabilities & V4L2_CAP_VBI_CAPTURE )
result = saa7146_vbi_uops . open ( dev , file ) ;
if ( dev - > ext_vv_data - > vbi_fops . open )
2008-12-30 12:58:20 +03:00
dev - > ext_vv_data - > vbi_fops . open ( file ) ;
2005-04-17 02:20:36 +04:00
} else {
2011-08-22 02:56:44 +04:00
DEB_S ( " initializing video... \n " ) ;
2005-04-17 02:20:36 +04:00
result = saa7146_video_uops . open ( dev , file ) ;
}
if ( 0 ! = result ) {
goto out ;
}
if ( 0 = = try_module_get ( dev - > ext - > module ) ) {
result = - EINVAL ;
goto out ;
}
result = 0 ;
out :
2008-03-29 06:07:38 +03:00
if ( fh & & result ! = 0 ) {
2005-04-17 02:20:36 +04:00
kfree ( fh ) ;
file - > private_data = NULL ;
}
2006-02-07 11:49:14 +03:00
mutex_unlock ( & saa7146_devices_lock ) ;
2005-12-12 11:37:27 +03:00
return result ;
2005-04-17 02:20:36 +04:00
}
2008-12-30 12:58:20 +03:00
static int fops_release ( struct file * file )
2005-04-17 02:20:36 +04:00
{
struct saa7146_fh * fh = file - > private_data ;
struct saa7146_dev * dev = fh - > dev ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " file:%p \n " , file ) ;
2005-04-17 02:20:36 +04:00
2006-02-07 11:49:14 +03:00
if ( mutex_lock_interruptible ( & saa7146_devices_lock ) )
2005-04-17 02:20:36 +04:00
return - ERESTARTSYS ;
if ( fh - > type = = V4L2_BUF_TYPE_VBI_CAPTURE ) {
2006-01-09 23:21:37 +03:00
if ( dev - > ext_vv_data - > capabilities & V4L2_CAP_VBI_CAPTURE )
saa7146_vbi_uops . release ( dev , file ) ;
if ( dev - > ext_vv_data - > vbi_fops . release )
2008-12-30 12:58:20 +03:00
dev - > ext_vv_data - > vbi_fops . release ( file ) ;
2005-04-17 02:20:36 +04:00
} else {
saa7146_video_uops . release ( dev , file ) ;
}
module_put ( dev - > ext - > module ) ;
file - > private_data = NULL ;
kfree ( fh ) ;
2006-02-07 11:49:14 +03:00
mutex_unlock ( & saa7146_devices_lock ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int fops_mmap ( struct file * file , struct vm_area_struct * vma )
{
struct saa7146_fh * fh = file - > private_data ;
struct videobuf_queue * q ;
switch ( fh - > type ) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE : {
2011-08-22 02:56:44 +04:00
DEB_EE ( " V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, vma:%p \n " ,
file , vma ) ;
2005-04-17 02:20:36 +04:00
q = & fh - > video_q ;
break ;
}
case V4L2_BUF_TYPE_VBI_CAPTURE : {
2011-08-22 02:56:44 +04:00
DEB_EE ( " V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, vma:%p \n " ,
file , vma ) ;
2005-04-17 02:20:36 +04:00
q = & fh - > vbi_q ;
break ;
}
default :
BUG ( ) ;
return 0 ;
}
2006-01-09 20:25:34 +03:00
2005-04-17 02:20:36 +04:00
return videobuf_mmap_mapper ( q , vma ) ;
}
static unsigned int fops_poll ( struct file * file , struct poll_table_struct * wait )
{
struct saa7146_fh * fh = file - > private_data ;
struct videobuf_buffer * buf = NULL ;
struct videobuf_queue * q ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " file:%p, poll:%p \n " , file , wait ) ;
2005-04-17 02:20:36 +04:00
if ( V4L2_BUF_TYPE_VBI_CAPTURE = = fh - > type ) {
if ( 0 = = fh - > vbi_q . streaming )
return videobuf_poll_stream ( file , & fh - > vbi_q , wait ) ;
q = & fh - > vbi_q ;
} else {
2011-08-22 02:56:44 +04:00
DEB_D ( " using video queue \n " ) ;
2005-04-17 02:20:36 +04:00
q = & fh - > video_q ;
}
if ( ! list_empty ( & q - > stream ) )
buf = list_entry ( q - > stream . next , struct videobuf_buffer , stream ) ;
if ( ! buf ) {
2011-08-22 02:56:44 +04:00
DEB_D ( " buf == NULL! \n " ) ;
2005-04-17 02:20:36 +04:00
return POLLERR ;
}
poll_wait ( file , & buf - > done , wait ) ;
2007-11-07 02:02:36 +03:00
if ( buf - > state = = VIDEOBUF_DONE | | buf - > state = = VIDEOBUF_ERROR ) {
2011-08-22 02:56:44 +04:00
DEB_D ( " poll succeeded! \n " ) ;
2005-04-17 02:20:36 +04:00
return POLLIN | POLLRDNORM ;
}
2011-08-22 02:56:44 +04:00
DEB_D ( " nothing to poll for, buf->state:%d \n " , buf - > state ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static ssize_t fops_read ( struct file * file , char __user * data , size_t count , loff_t * ppos )
{
struct saa7146_fh * fh = file - > private_data ;
switch ( fh - > type ) {
2011-08-22 02:56:44 +04:00
case V4L2_BUF_TYPE_VIDEO_CAPTURE :
/*
DEB_EE ( " V4L2_BUF_TYPE_VIDEO_CAPTURE: file:%p, data:%p, count:%lun " ,
file , data , ( unsigned long ) count ) ;
*/
2005-04-17 02:20:36 +04:00
return saa7146_video_uops . read ( file , data , count , ppos ) ;
2011-08-22 02:56:44 +04:00
case V4L2_BUF_TYPE_VBI_CAPTURE :
/*
DEB_EE ( " V4L2_BUF_TYPE_VBI_CAPTURE: file:%p, data:%p, count:%lu \n " ,
file , data , ( unsigned long ) count ) ;
*/
2006-01-09 23:21:37 +03:00
if ( fh - > dev - > ext_vv_data - > capabilities & V4L2_CAP_VBI_CAPTURE )
return saa7146_vbi_uops . read ( file , data , count , ppos ) ;
2011-08-22 02:56:44 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
default :
BUG ( ) ;
return 0 ;
}
}
2006-01-09 23:21:37 +03:00
static ssize_t fops_write ( struct file * file , const char __user * data , size_t count , loff_t * ppos )
{
struct saa7146_fh * fh = file - > private_data ;
switch ( fh - > type ) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE :
return - EINVAL ;
case V4L2_BUF_TYPE_VBI_CAPTURE :
if ( fh - > dev - > ext_vv_data - > vbi_fops . write )
return fh - > dev - > ext_vv_data - > vbi_fops . write ( file , data , count , ppos ) ;
else
return - EINVAL ;
default :
BUG ( ) ;
return - EINVAL ;
}
}
2008-12-30 12:58:20 +03:00
static const struct v4l2_file_operations video_fops =
2005-04-17 02:20:36 +04:00
{
. owner = THIS_MODULE ,
. open = fops_open ,
. release = fops_release ,
. read = fops_read ,
2006-01-09 23:21:37 +03:00
. write = fops_write ,
2005-04-17 02:20:36 +04:00
. poll = fops_poll ,
. mmap = fops_mmap ,
2010-12-18 15:20:59 +03:00
. unlocked_ioctl = video_ioctl2 ,
2005-04-17 02:20:36 +04:00
} ;
2005-06-24 09:05:33 +04:00
static void vv_callback ( struct saa7146_dev * dev , unsigned long status )
2005-04-17 02:20:36 +04:00
{
u32 isr = status ;
2005-12-12 11:37:27 +03:00
2011-08-22 02:56:44 +04:00
DEB_INT ( " dev:%p, isr:0x%08x \n " , dev , ( u32 ) status ) ;
2005-04-17 02:20:36 +04:00
if ( 0 ! = ( isr & ( MASK_27 ) ) ) {
2011-08-22 02:56:44 +04:00
DEB_INT ( " irq: RPS0 (0x%08x) \n " , isr ) ;
2005-04-17 02:20:36 +04:00
saa7146_video_uops . irq_done ( dev , isr ) ;
}
if ( 0 ! = ( isr & ( MASK_28 ) ) ) {
u32 mc2 = saa7146_read ( dev , MC2 ) ;
if ( 0 ! = ( mc2 & MASK_15 ) ) {
2011-08-22 02:56:44 +04:00
DEB_INT ( " irq: RPS1 vbi workaround (0x%08x) \n " , isr ) ;
2005-04-17 02:20:36 +04:00
wake_up ( & dev - > vv_data - > vbi_wq ) ;
saa7146_write ( dev , MC2 , MASK_31 ) ;
return ;
}
2011-08-22 02:56:44 +04:00
DEB_INT ( " irq: RPS1 (0x%08x) \n " , isr ) ;
2005-04-17 02:20:36 +04:00
saa7146_vbi_uops . irq_done ( dev , isr ) ;
}
}
int saa7146_vv_init ( struct saa7146_dev * dev , struct saa7146_ext_vv * ext_vv )
{
2009-02-08 02:42:33 +03:00
struct saa7146_vv * vv ;
2010-03-25 01:09:55 +03:00
int err ;
err = v4l2_device_register ( & dev - > pci - > dev , & dev - > v4l2_dev ) ;
if ( err )
return err ;
2009-02-08 02:42:33 +03:00
vv = kzalloc ( sizeof ( struct saa7146_vv ) , GFP_KERNEL ) ;
2009-01-19 01:59:11 +03:00
if ( vv = = NULL ) {
2011-08-22 02:56:44 +04:00
ERR ( " out of memory. aborting. \n " ) ;
2009-02-08 02:42:33 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
2009-01-19 01:59:11 +03:00
ext_vv - > ops = saa7146_video_ioctl_ops ;
ext_vv - > core_ops = & saa7146_video_ioctl_ops ;
2005-04-17 02:20:36 +04:00
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p \n " , dev ) ;
2005-04-17 02:20:36 +04:00
/* set default values for video parts of the saa7146 */
saa7146_write ( dev , BCS_CTRL , 0x80400040 ) ;
/* enable video-port pins */
saa7146_write ( dev , MC1 , ( MASK_10 | MASK_26 ) ) ;
/* save per-device extension data (one extension can
handle different devices that might need different
configuration data ) */
dev - > ext_vv_data = ext_vv ;
2005-12-12 11:37:27 +03:00
vv - > d_clipping . cpu_addr = pci_alloc_consistent ( dev - > pci , SAA7146_CLIPPING_MEM , & vv - > d_clipping . dma_handle ) ;
2005-04-17 02:20:36 +04:00
if ( NULL = = vv - > d_clipping . cpu_addr ) {
2011-08-22 02:56:44 +04:00
ERR ( " out of memory. aborting. \n " ) ;
2005-04-17 02:20:36 +04:00
kfree ( vv ) ;
return - 1 ;
}
memset ( vv - > d_clipping . cpu_addr , 0x0 , SAA7146_CLIPPING_MEM ) ;
saa7146_video_uops . init ( dev , vv ) ;
2006-01-09 23:21:37 +03:00
if ( dev - > ext_vv_data - > capabilities & V4L2_CAP_VBI_CAPTURE )
saa7146_vbi_uops . init ( dev , vv ) ;
2005-12-12 11:37:27 +03:00
2005-04-17 02:20:36 +04:00
dev - > vv_data = vv ;
dev - > vv_callback = & vv_callback ;
return 0 ;
}
2006-04-11 17:26:57 +04:00
EXPORT_SYMBOL_GPL ( saa7146_vv_init ) ;
2005-04-17 02:20:36 +04:00
int saa7146_vv_release ( struct saa7146_dev * dev )
{
struct saa7146_vv * vv = dev - > vv_data ;
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p \n " , dev ) ;
2005-12-12 11:37:27 +03:00
2009-02-08 02:42:33 +03:00
v4l2_device_unregister ( & dev - > v4l2_dev ) ;
2007-01-31 20:27:55 +03:00
pci_free_consistent ( dev - > pci , SAA7146_CLIPPING_MEM , vv - > d_clipping . cpu_addr , vv - > d_clipping . dma_handle ) ;
2005-12-12 11:37:27 +03:00
kfree ( vv ) ;
2005-04-17 02:20:36 +04:00
dev - > vv_data = NULL ;
dev - > vv_callback = NULL ;
2005-12-12 11:37:27 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-04-11 17:26:57 +04:00
EXPORT_SYMBOL_GPL ( saa7146_vv_release ) ;
2005-04-17 02:20:36 +04:00
int saa7146_register_device ( struct video_device * * vid , struct saa7146_dev * dev ,
char * name , int type )
{
struct video_device * vfd ;
2009-01-19 01:59:11 +03:00
int err ;
2009-01-27 01:13:05 +03:00
int i ;
2005-04-17 02:20:36 +04:00
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p, name:'%s', type:%d \n " , dev , name , type ) ;
2005-04-17 02:20:36 +04:00
// released by vfd->release
2005-12-12 11:37:27 +03:00
vfd = video_device_alloc ( ) ;
2005-04-17 02:20:36 +04:00
if ( vfd = = NULL )
return - ENOMEM ;
2009-01-19 01:59:11 +03:00
vfd - > fops = & video_fops ;
2009-01-27 01:13:05 +03:00
vfd - > ioctl_ops = & dev - > ext_vv_data - > ops ;
2005-04-17 02:20:36 +04:00
vfd - > release = video_device_release ;
2010-12-18 15:20:59 +03:00
vfd - > lock = & dev - > v4l2_lock ;
2009-01-27 01:13:05 +03:00
vfd - > tvnorms = 0 ;
for ( i = 0 ; i < dev - > ext_vv_data - > num_stds ; i + + )
vfd - > tvnorms | = dev - > ext_vv_data - > stds [ i ] . id ;
2009-01-19 01:59:11 +03:00
strlcpy ( vfd - > name , name , sizeof ( vfd - > name ) ) ;
2008-08-23 14:24:07 +04:00
video_set_drvdata ( vfd , dev ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
err = video_register_device ( vfd , type , - 1 ) ;
if ( err < 0 ) {
2011-08-22 02:56:44 +04:00
ERR ( " cannot register v4l2 device. skipping. \n " ) ;
V4L/DVB (7035): drivers/media/common: Add missing video_device_release
Video_device_alloc returns the result of a kzalloc. In this case, the
value is stored in a local variable which is not copied elsewhere before
the point of the error return (video_register_device does not save its
first argument anywhere if it returns a negative value). Thus, a
video_device_release it needed before the error return.
The problem was found using the following semantic match.
(http://www.emn.fr/x-info/coccinelle/)
// <smpl>
@@
type T,T1,T2;
identifier E;
statement S;
expression x1,x2,x3;
int ret;
@@
T E;
...
* E = video_device_alloc(...);
if (E == NULL) S
... when != video_device_release(...,(T1)E,...)
when != if (E != NULL) { ... video_device_release(...,(T1)E,...); ...}
when != x1 = (T1)E
when != E = x3;
when any
if (...) {
... when != video_device_release(...,(T2)E,...)
when != if (E != NULL) { ... video_device_release(...,(T2)E,...); ...}
when != x2 = (T2)E
(
* return;
|
* return ret;
)
}
// </smpl>
Signed-off-by: Julia Lawall <julia@diku.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
CC: Oliver Endriss <o.endriss@gmx.de>
CC: Michael Hunold <michael@mihu.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-01-12 04:03:42 +03:00
video_device_release ( vfd ) ;
2009-01-19 01:59:11 +03:00
return err ;
2005-04-17 02:20:36 +04:00
}
2011-08-22 02:56:44 +04:00
pr_info ( " %s: registered device %s [v4l2] \n " ,
dev - > name , video_device_node_name ( vfd ) ) ;
2005-04-17 02:20:36 +04:00
* vid = vfd ;
return 0 ;
}
2006-04-11 17:26:57 +04:00
EXPORT_SYMBOL_GPL ( saa7146_register_device ) ;
2005-04-17 02:20:36 +04:00
int saa7146_unregister_device ( struct video_device * * vid , struct saa7146_dev * dev )
{
2011-08-22 02:56:44 +04:00
DEB_EE ( " dev:%p \n " , dev ) ;
2005-04-17 02:20:36 +04:00
video_unregister_device ( * vid ) ;
* vid = NULL ;
return 0 ;
}
2006-04-11 17:26:57 +04:00
EXPORT_SYMBOL_GPL ( saa7146_unregister_device ) ;
2005-04-17 02:20:36 +04:00
static int __init saa7146_vv_init_module ( void )
{
return 0 ;
}
static void __exit saa7146_vv_cleanup_module ( void )
{
}
module_init ( saa7146_vv_init_module ) ;
module_exit ( saa7146_vv_cleanup_module ) ;
MODULE_AUTHOR ( " Michael Hunold <michael@mihu.de> " ) ;
MODULE_DESCRIPTION ( " video4linux driver for saa7146-based hardware " ) ;
MODULE_LICENSE ( " GPL " ) ;