2010-07-31 23:34:19 +04:00
/*
* Driver for the NXP SAA7164 PCIe bridge
*
2015-03-23 22:08:15 +03:00
* Copyright ( c ) 2010 - 2015 Steven Toth < stoth @ kernellabs . com >
2010-07-31 23:34:19 +04:00
*
* 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 .
*/
# include "saa7164.h"
/* Take the encoder configuration from the port struct and
* flush it to the hardware .
*/
static void saa7164_vbi_configure ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
dprintk ( DBGLVL_VBI , " %s() \n " , __func__ ) ;
2015-08-28 14:48:33 +03:00
port - > vbi_params . width = port - > enc_port - > width ;
port - > vbi_params . height = port - > enc_port - > height ;
2010-07-31 23:34:19 +04:00
port - > vbi_params . is_50hz =
2015-08-28 14:48:33 +03:00
( port - > enc_port - > encodernorm . id & V4L2_STD_625_50 ) ! = 0 ;
2010-07-31 23:34:19 +04:00
/* Set up the DIF (enable it) for analog mode by default */
saa7164_api_initialize_dif ( port ) ;
dprintk ( DBGLVL_VBI , " %s() ends \n " , __func__ ) ;
}
static int saa7164_vbi_buffers_dealloc ( struct saa7164_port * port )
{
struct list_head * c , * n , * p , * q , * l , * v ;
struct saa7164_dev * dev = port - > dev ;
struct saa7164_buffer * buf ;
struct saa7164_user_buffer * ubuf ;
/* Remove any allocated buffers */
mutex_lock ( & port - > dmaqueue_lock ) ;
dprintk ( DBGLVL_VBI , " %s(port=%d) dmaqueue \n " , __func__ , port - > nr ) ;
list_for_each_safe ( c , n , & port - > dmaqueue . list ) {
buf = list_entry ( c , struct saa7164_buffer , list ) ;
list_del ( c ) ;
saa7164_buffer_dealloc ( buf ) ;
}
dprintk ( DBGLVL_VBI , " %s(port=%d) used \n " , __func__ , port - > nr ) ;
list_for_each_safe ( p , q , & port - > list_buf_used . list ) {
ubuf = list_entry ( p , struct saa7164_user_buffer , list ) ;
list_del ( p ) ;
saa7164_buffer_dealloc_user ( ubuf ) ;
}
dprintk ( DBGLVL_VBI , " %s(port=%d) free \n " , __func__ , port - > nr ) ;
list_for_each_safe ( l , v , & port - > list_buf_free . list ) {
ubuf = list_entry ( l , struct saa7164_user_buffer , list ) ;
list_del ( l ) ;
saa7164_buffer_dealloc_user ( ubuf ) ;
}
mutex_unlock ( & port - > dmaqueue_lock ) ;
dprintk ( DBGLVL_VBI , " %s(port=%d) done \n " , __func__ , port - > nr ) ;
return 0 ;
}
/* Dynamic buffer switch at vbi start time */
static int saa7164_vbi_buffers_alloc ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
struct saa7164_buffer * buf ;
struct saa7164_user_buffer * ubuf ;
2010-10-12 00:17:45 +04:00
struct tmHWStreamParameters * params = & port - > hw_streamingparams ;
2010-07-31 23:34:19 +04:00
int result = - ENODEV , i ;
int len = 0 ;
dprintk ( DBGLVL_VBI , " %s() \n " , __func__ ) ;
/* TODO: NTSC SPECIFIC */
/* Init and establish defaults */
params - > samplesperline = 1440 ;
params - > numberoflines = 12 ;
params - > numberoflines = 18 ;
params - > pitch = 1600 ;
params - > pitch = 1440 ;
params - > numpagetables = 2 +
( ( params - > numberoflines * params - > pitch ) / PAGE_SIZE ) ;
params - > bitspersample = 8 ;
params - > linethreshold = 0 ;
2011-01-30 22:33:01 +03:00
params - > pagetablelistvirt = NULL ;
params - > pagetablelistphys = NULL ;
2010-07-31 23:34:19 +04:00
params - > numpagetableentries = port - > hwcfg . buffercount ;
/* Allocate the PCI resources, buffers (hard) */
for ( i = 0 ; i < port - > hwcfg . buffercount ; i + + ) {
buf = saa7164_buffer_alloc ( port ,
params - > numberoflines *
params - > pitch ) ;
if ( ! buf ) {
[media] saa7164: don't break long lines
Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.
As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.
So, join those continuation lines.
The patch was generated via the script below, and manually
adjusted if needed.
</script>
use Text::Tabs;
while (<>) {
if ($next ne "") {
$c=$_;
if ($c =~ /^\s+\"(.*)/) {
$c2=$1;
$next =~ s/\"\n$//;
$n = expand($next);
$funpos = index($n, '(');
$pos = index($c2, '",');
if ($funpos && $pos > 0) {
$s1 = substr $c2, 0, $pos + 2;
$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
$s2 =~ s/^\s+//;
$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");
print unexpand("$next$s1\n");
print unexpand("$s2\n") if ($s2 ne "");
} else {
print "$next$c2\n";
}
$next="";
next;
} else {
print $next;
}
$next="";
} else {
if (m/\"$/) {
if (!m/\\n\"$/) {
$next=$_;
next;
}
}
}
print $_;
}
</script>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2016-10-18 22:44:07 +03:00
printk ( KERN_ERR " %s() failed (errno = %d), unable to allocate buffer \n " ,
2010-07-31 23:34:19 +04:00
__func__ , result ) ;
result = - ENOMEM ;
goto failed ;
} else {
mutex_lock ( & port - > dmaqueue_lock ) ;
list_add_tail ( & buf - > list , & port - > dmaqueue . list ) ;
mutex_unlock ( & port - > dmaqueue_lock ) ;
}
}
2011-05-10 12:16:21 +04:00
/* Allocate some kernel buffers for copying
2010-07-31 23:34:19 +04:00
* to userpsace .
*/
len = params - > numberoflines * params - > pitch ;
if ( vbi_buffers < 16 )
vbi_buffers = 16 ;
if ( vbi_buffers > 512 )
vbi_buffers = 512 ;
for ( i = 0 ; i < vbi_buffers ; i + + ) {
ubuf = saa7164_buffer_alloc_user ( dev , len ) ;
if ( ubuf ) {
mutex_lock ( & port - > dmaqueue_lock ) ;
list_add_tail ( & ubuf - > list , & port - > list_buf_free . list ) ;
mutex_unlock ( & port - > dmaqueue_lock ) ;
}
}
result = 0 ;
failed :
return result ;
}
static int saa7164_vbi_initialize ( struct saa7164_port * port )
{
saa7164_vbi_configure ( port ) ;
return 0 ;
}
/* -- V4L2 --------------------------------------------------------- */
2013-03-15 13:10:40 +04:00
static int vidioc_s_std ( struct file * file , void * priv , v4l2_std_id id )
2010-07-31 23:34:19 +04:00
{
struct saa7164_vbi_fh * fh = file - > private_data ;
2015-08-28 14:48:33 +03:00
return saa7164_s_std ( fh - > port - > enc_port , id ) ;
2010-07-31 23:34:19 +04:00
}
2013-06-03 12:36:45 +04:00
static int vidioc_g_std ( struct file * file , void * priv , v4l2_std_id * id )
{
struct saa7164_encoder_fh * fh = file - > private_data ;
2010-07-31 23:34:19 +04:00
2015-08-28 14:48:33 +03:00
return saa7164_g_std ( fh - > port - > enc_port , id ) ;
2010-07-31 23:34:19 +04:00
}
static int vidioc_g_input ( struct file * file , void * priv , unsigned int * i )
{
struct saa7164_vbi_fh * fh = file - > private_data ;
2015-08-28 14:48:33 +03:00
return saa7164_g_input ( fh - > port - > enc_port , i ) ;
2010-07-31 23:34:19 +04:00
}
static int vidioc_s_input ( struct file * file , void * priv , unsigned int i )
{
struct saa7164_vbi_fh * fh = file - > private_data ;
2015-08-28 14:48:33 +03:00
return saa7164_s_input ( fh - > port - > enc_port , i ) ;
2010-07-31 23:34:19 +04:00
}
static int vidioc_g_frequency ( struct file * file , void * priv ,
struct v4l2_frequency * f )
{
struct saa7164_vbi_fh * fh = file - > private_data ;
2015-08-28 14:48:33 +03:00
return saa7164_g_frequency ( fh - > port - > enc_port , f ) ;
2010-07-31 23:34:19 +04:00
}
static int vidioc_s_frequency ( struct file * file , void * priv ,
2013-03-19 11:09:26 +04:00
const struct v4l2_frequency * f )
2010-07-31 23:34:19 +04:00
{
struct saa7164_vbi_fh * fh = file - > private_data ;
2015-08-28 14:48:33 +03:00
int ret = saa7164_s_frequency ( fh - > port - > enc_port , f ) ;
2010-07-31 23:34:19 +04:00
2015-08-28 14:48:33 +03:00
if ( ret = = 0 )
saa7164_vbi_initialize ( fh - > port ) ;
return ret ;
2010-07-31 23:34:19 +04:00
}
static int vidioc_querycap ( struct file * file , void * priv ,
struct v4l2_capability * cap )
{
struct saa7164_vbi_fh * fh = file - > private_data ;
struct saa7164_port * port = fh - > port ;
struct saa7164_dev * dev = port - > dev ;
2018-09-10 23:20:42 +03:00
strscpy ( cap - > driver , dev - > name , sizeof ( cap - > driver ) ) ;
2018-09-10 15:19:14 +03:00
strscpy ( cap - > card , saa7164_boards [ dev - > board ] . name ,
2010-07-31 23:34:19 +04:00
sizeof ( cap - > card ) ) ;
sprintf ( cap - > bus_info , " PCI:%s " , pci_name ( dev - > pci ) ) ;
2015-03-27 21:17:56 +03:00
cap - > device_caps =
2010-07-31 23:34:19 +04:00
V4L2_CAP_VBI_CAPTURE |
2015-03-27 21:17:56 +03:00
V4L2_CAP_READWRITE |
V4L2_CAP_TUNER ;
2010-07-31 23:34:19 +04:00
2015-03-27 21:17:56 +03:00
cap - > capabilities = cap - > device_caps |
V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_DEVICE_CAPS ;
2010-07-31 23:34:19 +04:00
return 0 ;
}
static int saa7164_vbi_stop_port ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
int ret ;
ret = saa7164_api_transition_port ( port , SAA_DMASTATE_STOP ) ;
if ( ( ret ! = SAA_OK ) & & ( ret ! = SAA_ERR_ALREADY_STOPPED ) ) {
printk ( KERN_ERR " %s() stop transition failed, ret = 0x%x \n " ,
__func__ , ret ) ;
ret = - EIO ;
} else {
dprintk ( DBGLVL_VBI , " %s() Stopped \n " , __func__ ) ;
ret = 0 ;
}
return ret ;
}
static int saa7164_vbi_acquire_port ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
int ret ;
ret = saa7164_api_transition_port ( port , SAA_DMASTATE_ACQUIRE ) ;
if ( ( ret ! = SAA_OK ) & & ( ret ! = SAA_ERR_ALREADY_STOPPED ) ) {
printk ( KERN_ERR " %s() acquire transition failed, ret = 0x%x \n " ,
__func__ , ret ) ;
ret = - EIO ;
} else {
dprintk ( DBGLVL_VBI , " %s() Acquired \n " , __func__ ) ;
ret = 0 ;
}
return ret ;
}
static int saa7164_vbi_pause_port ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
int ret ;
ret = saa7164_api_transition_port ( port , SAA_DMASTATE_PAUSE ) ;
if ( ( ret ! = SAA_OK ) & & ( ret ! = SAA_ERR_ALREADY_STOPPED ) ) {
printk ( KERN_ERR " %s() pause transition failed, ret = 0x%x \n " ,
__func__ , ret ) ;
ret = - EIO ;
} else {
dprintk ( DBGLVL_VBI , " %s() Paused \n " , __func__ ) ;
ret = 0 ;
}
return ret ;
}
/* Firmware is very windows centric, meaning you have to transition
* the part through AVStream / KS Windows stages , forwards or backwards .
* States are : stopped , acquired ( h / w ) , paused , started .
* We have to leave here will all of the soft buffers on the free list ,
* else the cfg_post ( ) func won ' t have soft buffers to correctly configure .
*/
static int saa7164_vbi_stop_streaming ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
struct saa7164_buffer * buf ;
struct saa7164_user_buffer * ubuf ;
struct list_head * c , * n ;
int ret ;
dprintk ( DBGLVL_VBI , " %s(port=%d) \n " , __func__ , port - > nr ) ;
ret = saa7164_vbi_pause_port ( port ) ;
ret = saa7164_vbi_acquire_port ( port ) ;
ret = saa7164_vbi_stop_port ( port ) ;
dprintk ( DBGLVL_VBI , " %s(port=%d) Hardware stopped \n " , __func__ ,
port - > nr ) ;
/* Reset the state of any allocated buffer resources */
mutex_lock ( & port - > dmaqueue_lock ) ;
/* Reset the hard and soft buffer state */
list_for_each_safe ( c , n , & port - > dmaqueue . list ) {
buf = list_entry ( c , struct saa7164_buffer , list ) ;
buf - > flags = SAA7164_BUFFER_FREE ;
buf - > pos = 0 ;
}
list_for_each_safe ( c , n , & port - > list_buf_used . list ) {
ubuf = list_entry ( c , struct saa7164_user_buffer , list ) ;
ubuf - > pos = 0 ;
list_move_tail ( & ubuf - > list , & port - > list_buf_free . list ) ;
}
mutex_unlock ( & port - > dmaqueue_lock ) ;
/* Free any allocated resources */
saa7164_vbi_buffers_dealloc ( port ) ;
dprintk ( DBGLVL_VBI , " %s(port=%d) Released \n " , __func__ , port - > nr ) ;
return ret ;
}
static int saa7164_vbi_start_streaming ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
int result , ret = 0 ;
dprintk ( DBGLVL_VBI , " %s(port=%d) \n " , __func__ , port - > nr ) ;
port - > done_first_interrupt = 0 ;
/* allocate all of the PCIe DMA buffer resources on the fly,
* allowing switching between TS and PS payloads without
* requiring a complete driver reload .
*/
saa7164_vbi_buffers_alloc ( port ) ;
/* Configure the encoder with any cache values */
2010-11-13 00:32:36 +03:00
#if 0
saa7164_api_set_encoder ( port ) ;
saa7164_api_get_encoder ( port ) ;
# endif
2010-07-31 23:34:19 +04:00
/* Place the empty buffers on the hardware */
saa7164_buffer_cfg_port ( port ) ;
/* Negotiate format */
if ( saa7164_api_set_vbi_format ( port ) ! = SAA_OK ) {
printk ( KERN_ERR " %s() No supported VBI format \n " , __func__ ) ;
ret = - EIO ;
goto out ;
}
/* Acquire the hardware */
result = saa7164_api_transition_port ( port , SAA_DMASTATE_ACQUIRE ) ;
if ( ( result ! = SAA_OK ) & & ( result ! = SAA_ERR_ALREADY_STOPPED ) ) {
printk ( KERN_ERR " %s() acquire transition failed, res = 0x%x \n " ,
__func__ , result ) ;
ret = - EIO ;
goto out ;
} else
dprintk ( DBGLVL_VBI , " %s() Acquired \n " , __func__ ) ;
/* Pause the hardware */
result = saa7164_api_transition_port ( port , SAA_DMASTATE_PAUSE ) ;
if ( ( result ! = SAA_OK ) & & ( result ! = SAA_ERR_ALREADY_STOPPED ) ) {
printk ( KERN_ERR " %s() pause transition failed, res = 0x%x \n " ,
__func__ , result ) ;
/* Stop the hardware, regardless */
result = saa7164_vbi_stop_port ( port ) ;
2012-04-20 09:50:45 +04:00
if ( result ! = SAA_OK ) {
[media] saa7164: don't break long lines
Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.
As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.
So, join those continuation lines.
The patch was generated via the script below, and manually
adjusted if needed.
</script>
use Text::Tabs;
while (<>) {
if ($next ne "") {
$c=$_;
if ($c =~ /^\s+\"(.*)/) {
$c2=$1;
$next =~ s/\"\n$//;
$n = expand($next);
$funpos = index($n, '(');
$pos = index($c2, '",');
if ($funpos && $pos > 0) {
$s1 = substr $c2, 0, $pos + 2;
$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
$s2 =~ s/^\s+//;
$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");
print unexpand("$next$s1\n");
print unexpand("$s2\n") if ($s2 ne "");
} else {
print "$next$c2\n";
}
$next="";
next;
} else {
print $next;
}
$next="";
} else {
if (m/\"$/) {
if (!m/\\n\"$/) {
$next=$_;
next;
}
}
}
print $_;
}
</script>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2016-10-18 22:44:07 +03:00
printk ( KERN_ERR " %s() pause/forced stop transition failed, res = 0x%x \n " ,
__func__ , result ) ;
2010-07-31 23:34:19 +04:00
}
ret = - EIO ;
goto out ;
} else
dprintk ( DBGLVL_VBI , " %s() Paused \n " , __func__ ) ;
/* Start the hardware */
result = saa7164_api_transition_port ( port , SAA_DMASTATE_RUN ) ;
if ( ( result ! = SAA_OK ) & & ( result ! = SAA_ERR_ALREADY_STOPPED ) ) {
printk ( KERN_ERR " %s() run transition failed, result = 0x%x \n " ,
__func__ , result ) ;
/* Stop the hardware, regardless */
result = saa7164_vbi_acquire_port ( port ) ;
result = saa7164_vbi_stop_port ( port ) ;
2012-04-20 09:50:45 +04:00
if ( result ! = SAA_OK ) {
[media] saa7164: don't break long lines
Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.
As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.
So, join those continuation lines.
The patch was generated via the script below, and manually
adjusted if needed.
</script>
use Text::Tabs;
while (<>) {
if ($next ne "") {
$c=$_;
if ($c =~ /^\s+\"(.*)/) {
$c2=$1;
$next =~ s/\"\n$//;
$n = expand($next);
$funpos = index($n, '(');
$pos = index($c2, '",');
if ($funpos && $pos > 0) {
$s1 = substr $c2, 0, $pos + 2;
$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
$s2 =~ s/^\s+//;
$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");
print unexpand("$next$s1\n");
print unexpand("$s2\n") if ($s2 ne "");
} else {
print "$next$c2\n";
}
$next="";
next;
} else {
print $next;
}
$next="";
} else {
if (m/\"$/) {
if (!m/\\n\"$/) {
$next=$_;
next;
}
}
}
print $_;
}
</script>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2016-10-18 22:44:07 +03:00
printk ( KERN_ERR " %s() run/forced stop transition failed, res = 0x%x \n " ,
__func__ , result ) ;
2010-07-31 23:34:19 +04:00
}
ret = - EIO ;
} else
dprintk ( DBGLVL_VBI , " %s() Running \n " , __func__ ) ;
out :
return ret ;
}
2012-10-27 20:11:11 +04:00
static int saa7164_vbi_fmt ( struct file * file , void * priv ,
struct v4l2_format * f )
2010-07-31 23:34:19 +04:00
{
/* ntsc */
f - > fmt . vbi . samples_per_line = 1440 ;
f - > fmt . vbi . sampling_rate = 27000000 ;
f - > fmt . vbi . sample_format = V4L2_PIX_FMT_GREY ;
f - > fmt . vbi . offset = 0 ;
f - > fmt . vbi . flags = 0 ;
f - > fmt . vbi . start [ 0 ] = 10 ;
f - > fmt . vbi . count [ 0 ] = 18 ;
f - > fmt . vbi . start [ 1 ] = 263 + 10 + 1 ;
f - > fmt . vbi . count [ 1 ] = 18 ;
2015-08-28 14:48:30 +03:00
memset ( f - > fmt . vbi . reserved , 0 , sizeof ( f - > fmt . vbi . reserved ) ) ;
2010-07-31 23:34:19 +04:00
return 0 ;
}
static int fops_open ( struct file * file )
{
2010-10-07 04:52:22 +04:00
struct saa7164_dev * dev ;
struct saa7164_port * port ;
2010-07-31 23:34:19 +04:00
struct saa7164_vbi_fh * fh ;
2010-10-07 04:52:22 +04:00
port = ( struct saa7164_port * ) video_get_drvdata ( video_devdata ( file ) ) ;
if ( ! port )
return - ENODEV ;
2010-07-31 23:34:19 +04:00
2010-10-07 04:52:22 +04:00
dev = port - > dev ;
2010-07-31 23:34:19 +04:00
2010-10-07 04:52:22 +04:00
dprintk ( DBGLVL_VBI , " %s() \n " , __func__ ) ;
2010-07-31 23:34:19 +04:00
/* allocate + initialize per filehandle data */
fh = kzalloc ( sizeof ( * fh ) , GFP_KERNEL ) ;
2010-10-07 04:52:22 +04:00
if ( NULL = = fh )
2010-07-31 23:34:19 +04:00
return - ENOMEM ;
fh - > port = port ;
2015-08-28 14:48:27 +03:00
v4l2_fh_init ( & fh - > fh , video_devdata ( file ) ) ;
v4l2_fh_add ( & fh - > fh ) ;
file - > private_data = fh ;
2010-07-31 23:34:19 +04:00
return 0 ;
}
static int fops_release ( struct file * file )
{
struct saa7164_vbi_fh * fh = file - > private_data ;
struct saa7164_port * port = fh - > port ;
struct saa7164_dev * dev = port - > dev ;
dprintk ( DBGLVL_VBI , " %s() \n " , __func__ ) ;
/* Shut device down on last close */
if ( atomic_cmpxchg ( & fh - > v4l_reading , 1 , 0 ) = = 1 ) {
if ( atomic_dec_return ( & port - > v4l_reader_count ) = = 0 ) {
/* stop vbi capture then cancel buffers */
saa7164_vbi_stop_streaming ( port ) ;
}
}
2015-08-28 14:48:27 +03:00
v4l2_fh_del ( & fh - > fh ) ;
v4l2_fh_exit ( & fh - > fh ) ;
2010-07-31 23:34:19 +04:00
kfree ( fh ) ;
return 0 ;
}
2012-10-27 20:11:11 +04:00
static struct
saa7164_user_buffer * saa7164_vbi_next_buf ( struct saa7164_port * port )
2010-07-31 23:34:19 +04:00
{
2011-01-30 22:33:01 +03:00
struct saa7164_user_buffer * ubuf = NULL ;
2010-07-31 23:34:19 +04:00
struct saa7164_dev * dev = port - > dev ;
u32 crc ;
mutex_lock ( & port - > dmaqueue_lock ) ;
if ( ! list_empty ( & port - > list_buf_used . list ) ) {
ubuf = list_first_entry ( & port - > list_buf_used . list ,
struct saa7164_user_buffer , list ) ;
if ( crc_checking ) {
crc = crc32 ( 0 , ubuf - > data , ubuf - > actual_size ) ;
if ( crc ! = ubuf - > crc ) {
2010-11-13 00:32:36 +03:00
printk ( KERN_ERR " %s() ubuf %p crc became invalid, was 0x%x became 0x%x \n " ,
__func__ ,
2010-07-31 23:34:19 +04:00
ubuf , ubuf - > crc , crc ) ;
}
}
}
mutex_unlock ( & port - > dmaqueue_lock ) ;
dprintk ( DBGLVL_VBI , " %s() returns %p \n " , __func__ , ubuf ) ;
return ubuf ;
}
static ssize_t fops_read ( struct file * file , char __user * buffer ,
size_t count , loff_t * pos )
{
struct saa7164_vbi_fh * fh = file - > private_data ;
struct saa7164_port * port = fh - > port ;
struct saa7164_user_buffer * ubuf = NULL ;
struct saa7164_dev * dev = port - > dev ;
2010-10-01 01:21:20 +04:00
int ret = 0 ;
2010-07-31 23:34:19 +04:00
int rem , cnt ;
u8 * p ;
port - > last_read_msecs_diff = port - > last_read_msecs ;
port - > last_read_msecs = jiffies_to_msecs ( jiffies ) ;
port - > last_read_msecs_diff = port - > last_read_msecs -
port - > last_read_msecs_diff ;
saa7164_histogram_update ( & port - > read_interval ,
port - > last_read_msecs_diff ) ;
if ( * pos ) {
printk ( KERN_ERR " %s() ESPIPE \n " , __func__ ) ;
return - ESPIPE ;
}
if ( atomic_cmpxchg ( & fh - > v4l_reading , 0 , 1 ) = = 0 ) {
if ( atomic_inc_return ( & port - > v4l_reader_count ) = = 1 ) {
if ( saa7164_vbi_initialize ( port ) < 0 ) {
printk ( KERN_ERR " %s() EINVAL \n " , __func__ ) ;
return - EINVAL ;
}
saa7164_vbi_start_streaming ( port ) ;
msleep ( 200 ) ;
}
}
/* blocking wait for buffer */
if ( ( file - > f_flags & O_NONBLOCK ) = = 0 ) {
if ( wait_event_interruptible ( port - > wait_read ,
saa7164_vbi_next_buf ( port ) ) ) {
printk ( KERN_ERR " %s() ERESTARTSYS \n " , __func__ ) ;
return - ERESTARTSYS ;
}
}
/* Pull the first buffer from the used list */
ubuf = saa7164_vbi_next_buf ( port ) ;
while ( ( count > 0 ) & & ubuf ) {
/* set remaining bytes to copy */
rem = ubuf - > actual_size - ubuf - > pos ;
cnt = rem > count ? count : rem ;
p = ubuf - > data + ubuf - > pos ;
dprintk ( DBGLVL_VBI ,
" %s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d \n " ,
__func__ , ( int ) count , cnt , rem , ubuf , ubuf - > pos ) ;
if ( copy_to_user ( buffer , p , cnt ) ) {
printk ( KERN_ERR " %s() copy_to_user failed \n " , __func__ ) ;
if ( ! ret ) {
printk ( KERN_ERR " %s() EFAULT \n " , __func__ ) ;
ret = - EFAULT ;
}
goto err ;
}
ubuf - > pos + = cnt ;
count - = cnt ;
buffer + = cnt ;
ret + = cnt ;
2010-11-13 00:32:36 +03:00
if ( ubuf - > pos > ubuf - > actual_size )
2010-07-31 23:34:19 +04:00
printk ( KERN_ERR " read() pos > actual, huh? \n " ) ;
if ( ubuf - > pos = = ubuf - > actual_size ) {
/* finished with current buffer, take next buffer */
/* Requeue the buffer on the free list */
ubuf - > pos = 0 ;
mutex_lock ( & port - > dmaqueue_lock ) ;
list_move_tail ( & ubuf - > list , & port - > list_buf_free . list ) ;
mutex_unlock ( & port - > dmaqueue_lock ) ;
/* Dequeue next */
if ( ( file - > f_flags & O_NONBLOCK ) = = 0 ) {
if ( wait_event_interruptible ( port - > wait_read ,
saa7164_vbi_next_buf ( port ) ) ) {
break ;
}
}
ubuf = saa7164_vbi_next_buf ( port ) ;
}
}
err :
if ( ! ret & & ! ubuf ) {
printk ( KERN_ERR " %s() EAGAIN \n " , __func__ ) ;
ret = - EAGAIN ;
}
return ret ;
}
2017-07-03 10:02:56 +03:00
static __poll_t fops_poll ( struct file * file , poll_table * wait )
2010-07-31 23:34:19 +04:00
{
struct saa7164_vbi_fh * fh = ( struct saa7164_vbi_fh * ) file - > private_data ;
struct saa7164_port * port = fh - > port ;
2017-07-03 10:02:56 +03:00
__poll_t mask = 0 ;
2010-07-31 23:34:19 +04:00
port - > last_poll_msecs_diff = port - > last_poll_msecs ;
port - > last_poll_msecs = jiffies_to_msecs ( jiffies ) ;
port - > last_poll_msecs_diff = port - > last_poll_msecs -
port - > last_poll_msecs_diff ;
saa7164_histogram_update ( & port - > poll_interval ,
port - > last_poll_msecs_diff ) ;
2010-11-13 00:32:36 +03:00
if ( ! video_is_registered ( port - > v4l_device ) )
2018-08-07 16:18:26 +03:00
return EPOLLERR ;
2010-07-31 23:34:19 +04:00
if ( atomic_cmpxchg ( & fh - > v4l_reading , 0 , 1 ) = = 0 ) {
if ( atomic_inc_return ( & port - > v4l_reader_count ) = = 1 ) {
if ( saa7164_vbi_initialize ( port ) < 0 )
2018-08-07 16:18:26 +03:00
return EPOLLERR ;
2010-07-31 23:34:19 +04:00
saa7164_vbi_start_streaming ( port ) ;
msleep ( 200 ) ;
}
}
/* blocking wait for buffer */
if ( ( file - > f_flags & O_NONBLOCK ) = = 0 ) {
if ( wait_event_interruptible ( port - > wait_read ,
saa7164_vbi_next_buf ( port ) ) ) {
2018-08-07 16:18:26 +03:00
return EPOLLERR ;
2010-07-31 23:34:19 +04:00
}
}
/* Pull the first buffer from the used list */
2010-11-24 08:36:57 +03:00
if ( ! list_empty ( & port - > list_buf_used . list ) )
2018-02-12 01:34:03 +03:00
mask | = EPOLLIN | EPOLLRDNORM ;
2010-07-31 23:34:19 +04:00
return mask ;
}
static const struct v4l2_file_operations vbi_fops = {
. owner = THIS_MODULE ,
. open = fops_open ,
. release = fops_release ,
. read = fops_read ,
. poll = fops_poll ,
. unlocked_ioctl = video_ioctl2 ,
} ;
static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
. vidioc_s_std = vidioc_s_std ,
2013-06-03 12:36:45 +04:00
. vidioc_g_std = vidioc_g_std ,
2015-08-28 14:48:33 +03:00
. vidioc_enum_input = saa7164_enum_input ,
2010-07-31 23:34:19 +04:00
. vidioc_g_input = vidioc_g_input ,
. vidioc_s_input = vidioc_s_input ,
2015-08-28 14:48:33 +03:00
. vidioc_g_tuner = saa7164_g_tuner ,
. vidioc_s_tuner = saa7164_s_tuner ,
2010-07-31 23:34:19 +04:00
. vidioc_g_frequency = vidioc_g_frequency ,
. vidioc_s_frequency = vidioc_s_frequency ,
. vidioc_querycap = vidioc_querycap ,
. vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt ,
. vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt ,
. vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt ,
} ;
static struct video_device saa7164_vbi_template = {
. name = " saa7164 " ,
. fops = & vbi_fops ,
. ioctl_ops = & vbi_ioctl_ops ,
. minor = - 1 ,
. tvnorms = SAA7164_NORMS ,
} ;
static struct video_device * saa7164_vbi_alloc (
struct saa7164_port * port ,
struct pci_dev * pci ,
struct video_device * template ,
char * type )
{
struct video_device * vfd ;
struct saa7164_dev * dev = port - > dev ;
dprintk ( DBGLVL_VBI , " %s() \n " , __func__ ) ;
vfd = video_device_alloc ( ) ;
if ( NULL = = vfd )
return NULL ;
* vfd = * template ;
snprintf ( vfd - > name , sizeof ( vfd - > name ) , " %s %s (%s) " , dev - > name ,
type , saa7164_boards [ dev - > board ] . name ) ;
2013-06-12 12:49:50 +04:00
vfd - > v4l2_dev = & dev - > v4l2_dev ;
2010-07-31 23:34:19 +04:00
vfd - > release = video_device_release ;
return vfd ;
}
int saa7164_vbi_register ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
int result = - ENODEV ;
dprintk ( DBGLVL_VBI , " %s() \n " , __func__ ) ;
if ( port - > type ! = SAA7164_MPEG_VBI )
BUG ( ) ;
/* Sanity check that the PCI configuration space is active */
if ( port - > hwcfg . BARLocation = = 0 ) {
[media] saa7164: don't break long lines
Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.
As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.
So, join those continuation lines.
The patch was generated via the script below, and manually
adjusted if needed.
</script>
use Text::Tabs;
while (<>) {
if ($next ne "") {
$c=$_;
if ($c =~ /^\s+\"(.*)/) {
$c2=$1;
$next =~ s/\"\n$//;
$n = expand($next);
$funpos = index($n, '(');
$pos = index($c2, '",');
if ($funpos && $pos > 0) {
$s1 = substr $c2, 0, $pos + 2;
$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
$s2 =~ s/^\s+//;
$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");
print unexpand("$next$s1\n");
print unexpand("$s2\n") if ($s2 ne "");
} else {
print "$next$c2\n";
}
$next="";
next;
} else {
print $next;
}
$next="";
} else {
if (m/\"$/) {
if (!m/\\n\"$/) {
$next=$_;
next;
}
}
}
print $_;
}
</script>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2016-10-18 22:44:07 +03:00
printk ( KERN_ERR " %s() failed (errno = %d), NO PCI configuration \n " ,
2010-07-31 23:34:19 +04:00
__func__ , result ) ;
result = - ENOMEM ;
goto failed ;
}
/* Establish VBI defaults here */
/* Allocate and register the video device node */
port - > v4l_device = saa7164_vbi_alloc ( port ,
dev - > pci , & saa7164_vbi_template , " vbi " ) ;
2011-01-30 22:33:01 +03:00
if ( ! port - > v4l_device ) {
2010-07-31 23:34:19 +04:00
printk ( KERN_INFO " %s: can't allocate vbi device \n " ,
dev - > name ) ;
result = - ENOMEM ;
goto failed ;
}
2015-08-28 14:48:33 +03:00
port - > enc_port = & dev - > ports [ port - > nr - 2 ] ;
2010-10-07 04:52:22 +04:00
video_set_drvdata ( port - > v4l_device , port ) ;
2010-07-31 23:34:19 +04:00
result = video_register_device ( port - > v4l_device ,
VFL_TYPE_VBI , - 1 ) ;
if ( result < 0 ) {
printk ( KERN_INFO " %s: can't register vbi device \n " ,
dev - > name ) ;
/* TODO: We're going to leak here if we don't dealloc
The buffers above . The unreg function can ' t deal wit it .
*/
goto failed ;
}
printk ( KERN_INFO " %s: registered device vbi%d [vbi] \n " ,
dev - > name , port - > v4l_device - > num ) ;
/* Configure the hardware defaults */
result = 0 ;
failed :
return result ;
}
void saa7164_vbi_unregister ( struct saa7164_port * port )
{
struct saa7164_dev * dev = port - > dev ;
dprintk ( DBGLVL_VBI , " %s(port=%d) \n " , __func__ , port - > nr ) ;
if ( port - > type ! = SAA7164_MPEG_VBI )
BUG ( ) ;
if ( port - > v4l_device ) {
if ( port - > v4l_device - > minor ! = - 1 )
video_unregister_device ( port - > v4l_device ) ;
else
video_device_release ( port - > v4l_device ) ;
port - > v4l_device = NULL ;
}
}