2019-05-27 08:55:06 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-04-28 20:24:33 -03:00
/*
* cx18 file operation functions
*
* Derived from ivtv - fileops . c
*
* Copyright ( C ) 2007 Hans Verkuil < hverkuil @ xs4all . nl >
2010-05-23 18:53:35 -03:00
* Copyright ( C ) 2008 Andy Walls < awalls @ md . metrocast . net >
2008-04-28 20:24:33 -03:00
*/
# include "cx18-driver.h"
# include "cx18-fileops.h"
# include "cx18-i2c.h"
# include "cx18-queue.h"
# include "cx18-vbi.h"
# include "cx18-audio.h"
# include "cx18-mailbox.h"
# include "cx18-scb.h"
# include "cx18-streams.h"
# include "cx18-controls.h"
# include "cx18-ioctl.h"
# include "cx18-cards.h"
2015-04-02 08:34:29 -03:00
# include <media/v4l2-event.h>
2008-04-28 20:24:33 -03:00
/* This function tries to claim the stream for a specific file descriptor.
If no one else is using this stream then the stream is claimed and
2009-12-31 17:19:25 -03:00
associated VBI and IDX streams are also automatically claimed .
2008-04-28 20:24:33 -03:00
Possible error returns : - EBUSY if someone else has claimed
the stream or 0 on success . */
2009-11-19 22:52:30 -03:00
int cx18_claim_stream ( struct cx18_open_id * id , int type )
2008-04-28 20:24:33 -03:00
{
struct cx18 * cx = id - > cx ;
struct cx18_stream * s = & cx - > streams [ type ] ;
2009-12-31 17:19:25 -03:00
struct cx18_stream * s_assoc ;
/* Nothing should ever try to directly claim the IDX stream */
if ( type = = CX18_ENC_STREAM_TYPE_IDX ) {
[media] cx18: 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 17:44:03 -02:00
CX18_WARN ( " MPEG Index stream cannot be claimed directly, but something tried. \n " ) ;
2009-12-31 17:19:25 -03:00
return - EINVAL ;
}
2008-04-28 20:24:33 -03:00
if ( test_and_set_bit ( CX18_F_S_CLAIMED , & s - > s_flags ) ) {
/* someone already claimed this stream */
if ( s - > id = = id - > open_id ) {
/* yes, this file descriptor did. So that's OK. */
return 0 ;
}
if ( s - > id = = - 1 & & type = = CX18_ENC_STREAM_TYPE_VBI ) {
/* VBI is handled already internally, now also assign
the file descriptor to this stream for external
reading of the stream . */
s - > id = id - > open_id ;
CX18_DEBUG_INFO ( " Start Read VBI \n " ) ;
return 0 ;
}
/* someone else is using this stream already */
CX18_DEBUG_INFO ( " Stream %d is busy \n " , type ) ;
return - EBUSY ;
}
s - > id = id - > open_id ;
2009-12-31 17:19:25 -03:00
/*
* CX18_ENC_STREAM_TYPE_MPG needs to claim :
* CX18_ENC_STREAM_TYPE_VBI , if VBI insertion is on for sliced VBI , or
* CX18_ENC_STREAM_TYPE_IDX , if VBI insertion is off for sliced VBI
* ( We don ' t yet fix up MPEG Index entries for our inserted packets ) .
*
* For all other streams we ' re done .
*/
if ( type ! = CX18_ENC_STREAM_TYPE_MPG )
return 0 ;
s_assoc = & cx - > streams [ CX18_ENC_STREAM_TYPE_IDX ] ;
if ( cx - > vbi . insert_mpeg & & ! cx18_raw_vbi ( cx ) )
s_assoc = & cx - > streams [ CX18_ENC_STREAM_TYPE_VBI ] ;
else if ( ! cx18_stream_enabled ( s_assoc ) )
2008-04-28 20:24:33 -03:00
return 0 ;
2009-12-31 17:19:25 -03:00
set_bit ( CX18_F_S_CLAIMED , & s_assoc - > s_flags ) ;
2008-04-28 20:24:33 -03:00
/* mark that it is used internally */
2009-12-31 17:19:25 -03:00
set_bit ( CX18_F_S_INTERNAL_USE , & s_assoc - > s_flags ) ;
2008-04-28 20:24:33 -03:00
return 0 ;
}
2009-11-19 22:52:30 -03:00
EXPORT_SYMBOL ( cx18_claim_stream ) ;
2008-04-28 20:24:33 -03:00
/* This function releases a previously claimed stream. It will take into
account associated VBI streams . */
2009-11-19 22:52:30 -03:00
void cx18_release_stream ( struct cx18_stream * s )
2008-04-28 20:24:33 -03:00
{
struct cx18 * cx = s - > cx ;
2009-12-31 17:19:25 -03:00
struct cx18_stream * s_assoc ;
2008-04-28 20:24:33 -03:00
s - > id = - 1 ;
2009-12-31 17:19:25 -03:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_IDX ) {
/*
* The IDX stream is only used internally , and can
* only be indirectly unclaimed by unclaiming the MPG stream .
*/
return ;
}
2008-04-28 20:24:33 -03:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_VBI & &
test_bit ( CX18_F_S_INTERNAL_USE , & s - > s_flags ) ) {
/* this stream is still in use internally */
return ;
}
if ( ! test_and_clear_bit ( CX18_F_S_CLAIMED , & s - > s_flags ) ) {
CX18_DEBUG_WARN ( " Release stream %s not in use! \n " , s - > name ) ;
return ;
}
cx18_flush_queues ( s ) ;
2009-12-31 17:19:25 -03:00
/*
* CX18_ENC_STREAM_TYPE_MPG needs to release the
* CX18_ENC_STREAM_TYPE_VBI and / or CX18_ENC_STREAM_TYPE_IDX streams .
*
* For all other streams we ' re done .
*/
if ( s - > type ! = CX18_ENC_STREAM_TYPE_MPG )
2008-04-28 20:24:33 -03:00
return ;
2009-12-31 17:19:25 -03:00
/* Unclaim the associated MPEG Index stream */
s_assoc = & cx - > streams [ CX18_ENC_STREAM_TYPE_IDX ] ;
if ( test_and_clear_bit ( CX18_F_S_INTERNAL_USE , & s_assoc - > s_flags ) ) {
clear_bit ( CX18_F_S_CLAIMED , & s_assoc - > s_flags ) ;
cx18_flush_queues ( s_assoc ) ;
2008-04-28 20:24:33 -03:00
}
2009-12-31 17:19:25 -03:00
/* Unclaim the associated VBI stream */
s_assoc = & cx - > streams [ CX18_ENC_STREAM_TYPE_VBI ] ;
if ( test_and_clear_bit ( CX18_F_S_INTERNAL_USE , & s_assoc - > s_flags ) ) {
if ( s_assoc - > id = = - 1 ) {
/*
* The VBI stream is not still claimed by a file
* descriptor , so completely unclaim it .
*/
clear_bit ( CX18_F_S_CLAIMED , & s_assoc - > s_flags ) ;
cx18_flush_queues ( s_assoc ) ;
}
2008-04-28 20:24:33 -03:00
}
}
2009-11-19 22:52:30 -03:00
EXPORT_SYMBOL ( cx18_release_stream ) ;
2008-04-28 20:24:33 -03:00
static void cx18_dualwatch ( struct cx18 * cx )
{
struct v4l2_tuner vt ;
2009-01-01 19:02:31 -03:00
u32 new_stereo_mode ;
const u32 dual = 0x0200 ;
2008-04-28 20:24:33 -03:00
2010-12-31 10:22:52 -03:00
new_stereo_mode = v4l2_ctrl_g_ctrl ( cx - > cxhdl . audio_mode ) ;
2008-04-28 20:24:33 -03:00
memset ( & vt , 0 , sizeof ( vt ) ) ;
2009-02-20 23:52:13 -03:00
cx18_call_all ( cx , tuner , g_tuner , & vt ) ;
2008-04-28 20:24:33 -03:00
if ( vt . audmode = = V4L2_TUNER_MODE_LANG1_LANG2 & &
( vt . rxsubchans & V4L2_TUNER_SUB_LANG2 ) )
new_stereo_mode = dual ;
if ( new_stereo_mode = = cx - > dualwatch_stereo_mode )
return ;
2010-12-31 10:22:52 -03:00
CX18_DEBUG_INFO ( " dualwatch: change stereo flag from 0x%x to 0x%x. \n " ,
cx - > dualwatch_stereo_mode , new_stereo_mode ) ;
if ( v4l2_ctrl_s_ctrl ( cx - > cxhdl . audio_mode , new_stereo_mode ) )
CX18_DEBUG_INFO ( " dualwatch: changing stereo flag failed \n " ) ;
2008-04-28 20:24:33 -03:00
}
2009-11-08 23:45:24 -03:00
static struct cx18_mdl * cx18_get_mdl ( struct cx18_stream * s , int non_block ,
int * err )
2008-04-28 20:24:33 -03:00
{
struct cx18 * cx = s - > cx ;
struct cx18_stream * s_vbi = & cx - > streams [ CX18_ENC_STREAM_TYPE_VBI ] ;
2009-11-08 23:45:24 -03:00
struct cx18_mdl * mdl ;
2008-04-28 20:24:33 -03:00
DEFINE_WAIT ( wait ) ;
* err = 0 ;
while ( 1 ) {
if ( s - > type = = CX18_ENC_STREAM_TYPE_MPG ) {
2009-12-31 22:27:28 -03:00
/* Process pending program updates and VBI data */
2008-04-28 20:24:33 -03:00
if ( time_after ( jiffies , cx - > dualwatch_jiffies + msecs_to_jiffies ( 1000 ) ) ) {
cx - > dualwatch_jiffies = jiffies ;
cx18_dualwatch ( cx ) ;
}
if ( test_bit ( CX18_F_S_INTERNAL_USE , & s_vbi - > s_flags ) & &
! test_bit ( CX18_F_S_APPL_IO , & s_vbi - > s_flags ) ) {
2009-11-08 23:45:24 -03:00
while ( ( mdl = cx18_dequeue ( s_vbi ,
& s_vbi - > q_full ) ) ) {
2008-04-28 20:24:33 -03:00
/* byteswap and process VBI data */
2009-11-08 23:45:24 -03:00
cx18_process_vbi_data ( cx , mdl ,
2008-12-12 20:00:29 -03:00
s_vbi - > type ) ;
2009-11-08 23:45:24 -03:00
cx18_stream_put_mdl_fw ( s_vbi , mdl ) ;
2008-04-28 20:24:33 -03:00
}
}
2009-11-08 23:45:24 -03:00
mdl = & cx - > vbi . sliced_mpeg_mdl ;
if ( mdl - > readpos ! = mdl - > bytesused )
return mdl ;
2008-04-28 20:24:33 -03:00
}
/* do we have new data? */
2009-11-08 23:45:24 -03:00
mdl = cx18_dequeue ( s , & s - > q_full ) ;
if ( mdl ) {
if ( ! test_and_clear_bit ( CX18_F_M_NEED_SWAP ,
& mdl - > m_flags ) )
return mdl ;
2008-04-28 20:24:33 -03:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_MPG )
/* byteswap MPG data */
2009-11-08 23:45:24 -03:00
cx18_mdl_swap ( mdl ) ;
2008-04-28 20:24:33 -03:00
else {
/* byteswap and process VBI data */
2009-11-08 23:45:24 -03:00
cx18_process_vbi_data ( cx , mdl , s - > type ) ;
2008-04-28 20:24:33 -03:00
}
2009-11-08 23:45:24 -03:00
return mdl ;
2008-04-28 20:24:33 -03:00
}
/* return if end of stream */
if ( ! test_bit ( CX18_F_S_STREAMING , & s - > s_flags ) ) {
CX18_DEBUG_INFO ( " EOS %s \n " , s - > name ) ;
return NULL ;
}
/* return if file was opened with O_NONBLOCK */
if ( non_block ) {
* err = - EAGAIN ;
return NULL ;
}
/* wait for more data to arrive */
prepare_to_wait ( & s - > waitq , & wait , TASK_INTERRUPTIBLE ) ;
/* New buffers might have become available before we were added
to the waitqueue */
2009-11-04 23:13:58 -03:00
if ( ! atomic_read ( & s - > q_full . depth ) )
2008-04-28 20:24:33 -03:00
schedule ( ) ;
finish_wait ( & s - > waitq , & wait ) ;
if ( signal_pending ( current ) ) {
/* return if a signal was received */
CX18_DEBUG_INFO ( " User stopped %s \n " , s - > name ) ;
* err = - EINTR ;
return NULL ;
}
}
}
2009-11-08 23:45:24 -03:00
static void cx18_setup_sliced_vbi_mdl ( struct cx18 * cx )
2008-04-28 20:24:33 -03:00
{
2009-11-08 23:45:24 -03:00
struct cx18_mdl * mdl = & cx - > vbi . sliced_mpeg_mdl ;
struct cx18_buffer * buf = & cx - > vbi . sliced_mpeg_buf ;
2008-04-28 20:24:33 -03:00
int idx = cx - > vbi . inserted_frame % CX18_VBI_FRAMES ;
2009-11-08 23:45:24 -03:00
buf - > buf = cx - > vbi . sliced_mpeg_data [ idx ] ;
buf - > bytesused = cx - > vbi . sliced_mpeg_size [ idx ] ;
buf - > readpos = 0 ;
mdl - > curr_buf = NULL ;
mdl - > bytesused = cx - > vbi . sliced_mpeg_size [ idx ] ;
mdl - > readpos = 0 ;
2008-04-28 20:24:33 -03:00
}
static size_t cx18_copy_buf_to_user ( struct cx18_stream * s ,
2009-11-08 23:45:24 -03:00
struct cx18_buffer * buf , char __user * ubuf , size_t ucount , bool * stop )
2008-04-28 20:24:33 -03:00
{
struct cx18 * cx = s - > cx ;
size_t len = buf - > bytesused - buf - > readpos ;
2009-11-08 23:45:24 -03:00
* stop = false ;
2008-04-28 20:24:33 -03:00
if ( len > ucount )
len = ucount ;
if ( cx - > vbi . insert_mpeg & & s - > type = = CX18_ENC_STREAM_TYPE_MPG & &
2008-12-12 16:24:04 -03:00
! cx18_raw_vbi ( cx ) & & buf ! = & cx - > vbi . sliced_mpeg_buf ) {
2009-01-31 00:33:02 -03:00
/*
* Try to find a good splice point in the PS , just before
* an MPEG - 2 Program Pack start code , and provide only
* up to that point to the user , so it ' s easy to insert VBI data
* the next time around .
2009-04-26 16:34:36 -03:00
*
* This will not work for an MPEG - 2 TS and has only been
* verified by analysis to work for an MPEG - 2 PS . Helen Buus
* pointed out this works for the CX23416 MPEG - 2 DVD compatible
* stream , and research indicates both the MPEG 2 SVCD and DVD
* stream types use an MPEG - 2 PS container .
2009-01-31 00:33:02 -03:00
*/
/*
* An MPEG - 2 Program Stream ( PS ) is a series of
* MPEG - 2 Program Packs terminated by an
* MPEG Program End Code after the last Program Pack .
* A Program Pack may hold a PS System Header packet and any
* number of Program Elementary Stream ( PES ) Packets
*/
2008-04-28 20:24:33 -03:00
const char * start = buf - > buf + buf - > readpos ;
const char * p = start + 1 ;
const u8 * q ;
u8 ch = cx - > search_pack_header ? 0xba : 0xe0 ;
int stuffing , i ;
while ( start + len > p ) {
2009-01-31 00:33:02 -03:00
/* Scan for a 0 to find a potential MPEG-2 start code */
2008-04-28 20:24:33 -03:00
q = memchr ( p , 0 , start + len - p ) ;
if ( q = = NULL )
break ;
p = q + 1 ;
2009-01-31 00:33:02 -03:00
/*
* Keep looking if not a
* MPEG - 2 Pack header start code : 0x00 0x00 0x01 0xba
* or MPEG - 2 video PES start code : 0x00 0x00 0x01 0xe0
*/
2008-04-28 20:24:33 -03:00
if ( ( char * ) q + 15 > = buf - > buf + buf - > bytesused | |
q [ 1 ] ! = 0 | | q [ 2 ] ! = 1 | | q [ 3 ] ! = ch )
continue ;
2009-01-31 00:33:02 -03:00
/* If expecting the primary video PES */
2008-04-28 20:24:33 -03:00
if ( ! cx - > search_pack_header ) {
2009-01-31 00:33:02 -03:00
/* Continue if it couldn't be a PES packet */
2008-04-28 20:24:33 -03:00
if ( ( q [ 6 ] & 0xc0 ) ! = 0x80 )
continue ;
2009-01-31 00:33:02 -03:00
/* Check if a PTS or PTS & DTS follow */
if ( ( ( q [ 7 ] & 0xc0 ) = = 0x80 & & /* PTS only */
( q [ 9 ] & 0xf0 ) = = 0x20 ) | | /* PTS only */
( ( q [ 7 ] & 0xc0 ) = = 0xc0 & & /* PTS & DTS */
( q [ 9 ] & 0xf0 ) = = 0x30 ) ) { /* DTS follows */
/* Assume we found the video PES hdr */
ch = 0xba ; /* next want a Program Pack*/
2008-04-28 20:24:33 -03:00
cx - > search_pack_header = 1 ;
2009-01-31 00:33:02 -03:00
p = q + 9 ; /* Skip this video PES hdr */
2008-04-28 20:24:33 -03:00
}
continue ;
}
2009-01-31 00:33:02 -03:00
/* We may have found a Program Pack start code */
/* Get the count of stuffing bytes & verify them */
2008-04-28 20:24:33 -03:00
stuffing = q [ 13 ] & 7 ;
/* all stuffing bytes must be 0xff */
for ( i = 0 ; i < stuffing ; i + + )
if ( q [ 14 + i ] ! = 0xff )
break ;
2009-01-31 00:33:02 -03:00
if ( i = = stuffing & & /* right number of stuffing bytes*/
( q [ 4 ] & 0xc4 ) = = 0x44 & & /* marker check */
( q [ 12 ] & 3 ) = = 3 & & /* marker check */
q [ 14 + stuffing ] = = 0 & & /* PES Pack or Sys Hdr */
2008-04-28 20:24:33 -03:00
q [ 15 + stuffing ] = = 0 & &
q [ 16 + stuffing ] = = 1 ) {
2009-01-31 00:33:02 -03:00
/* We declare we actually found a Program Pack*/
cx - > search_pack_header = 0 ; /* expect vid PES */
2008-04-28 20:24:33 -03:00
len = ( char * ) q - start ;
2009-11-08 23:45:24 -03:00
cx18_setup_sliced_vbi_mdl ( cx ) ;
* stop = true ;
2008-04-28 20:24:33 -03:00
break ;
}
}
}
if ( copy_to_user ( ubuf , ( u8 * ) buf - > buf + buf - > readpos , len ) ) {
CX18_DEBUG_WARN ( " copy %zd bytes to user failed for %s \n " ,
len , s - > name ) ;
return - EFAULT ;
}
buf - > readpos + = len ;
if ( s - > type = = CX18_ENC_STREAM_TYPE_MPG & &
buf ! = & cx - > vbi . sliced_mpeg_buf )
cx - > mpg_data_received + = len ;
return len ;
}
2009-11-08 23:45:24 -03:00
static size_t cx18_copy_mdl_to_user ( struct cx18_stream * s ,
struct cx18_mdl * mdl , char __user * ubuf , size_t ucount )
{
size_t tot_written = 0 ;
int rc ;
bool stop = false ;
if ( mdl - > curr_buf = = NULL )
mdl - > curr_buf = list_first_entry ( & mdl - > buf_list ,
struct cx18_buffer , list ) ;
if ( list_entry_is_past_end ( mdl - > curr_buf , & mdl - > buf_list , list ) ) {
/*
* For some reason we ' ve exhausted the buffers , but the MDL
* object still said some data was unread .
* Fix that and bail out .
*/
mdl - > readpos = mdl - > bytesused ;
return 0 ;
}
list_for_each_entry_from ( mdl - > curr_buf , & mdl - > buf_list , list ) {
if ( mdl - > curr_buf - > readpos > = mdl - > curr_buf - > bytesused )
continue ;
rc = cx18_copy_buf_to_user ( s , mdl - > curr_buf , ubuf + tot_written ,
ucount - tot_written , & stop ) ;
if ( rc < 0 )
return rc ;
mdl - > readpos + = rc ;
tot_written + = rc ;
if ( stop | | /* Forced stopping point for VBI insertion */
2019-02-18 14:28:59 -05:00
tot_written > = ucount | | /* Reader request satisfied */
2009-11-08 23:45:24 -03:00
mdl - > curr_buf - > readpos < mdl - > curr_buf - > bytesused | |
mdl - > readpos > = mdl - > bytesused ) /* MDL buffers drained */
break ;
}
return tot_written ;
}
2008-04-28 20:24:33 -03:00
static ssize_t cx18_read ( struct cx18_stream * s , char __user * ubuf ,
size_t tot_count , int non_block )
{
struct cx18 * cx = s - > cx ;
size_t tot_written = 0 ;
int single_frame = 0 ;
2008-05-25 11:21:27 -03:00
if ( atomic_read ( & cx - > ana_capturing ) = = 0 & & s - > id = = - 1 ) {
2008-04-28 20:24:33 -03:00
/* shouldn't happen */
CX18_DEBUG_WARN ( " Stream %s not initialized before read \n " ,
s - > name ) ;
return - EIO ;
}
/* Each VBI buffer is one frame, the v4l2 API says that for VBI the
frames should arrive one - by - one , so make sure we never output more
than one VBI frame at a time */
2008-12-12 16:24:04 -03:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_VBI & & ! cx18_raw_vbi ( cx ) )
2008-04-28 20:24:33 -03:00
single_frame = 1 ;
for ( ; ; ) {
2009-11-08 23:45:24 -03:00
struct cx18_mdl * mdl ;
2008-04-28 20:24:33 -03:00
int rc ;
2009-11-08 23:45:24 -03:00
mdl = cx18_get_mdl ( s , non_block , & rc ) ;
2008-04-28 20:24:33 -03:00
/* if there is no data available... */
2009-11-08 23:45:24 -03:00
if ( mdl = = NULL ) {
2008-04-28 20:24:33 -03:00
/* if we got data, then return that regardless */
if ( tot_written )
break ;
/* EOS condition */
if ( rc = = 0 ) {
clear_bit ( CX18_F_S_STREAMOFF , & s - > s_flags ) ;
clear_bit ( CX18_F_S_APPL_IO , & s - > s_flags ) ;
cx18_release_stream ( s ) ;
}
/* set errno */
return rc ;
}
2009-11-08 23:45:24 -03:00
rc = cx18_copy_mdl_to_user ( s , mdl , ubuf + tot_written ,
2008-04-28 20:24:33 -03:00
tot_count - tot_written ) ;
2009-11-08 23:45:24 -03:00
if ( mdl ! = & cx - > vbi . sliced_mpeg_mdl ) {
if ( mdl - > readpos = = mdl - > bytesused )
cx18_stream_put_mdl_fw ( s , mdl ) ;
2008-12-08 23:02:45 -03:00
else
2009-11-08 23:45:24 -03:00
cx18_push ( s , mdl , & s - > q_full ) ;
} else if ( mdl - > readpos = = mdl - > bytesused ) {
2008-04-28 20:24:33 -03:00
int idx = cx - > vbi . inserted_frame % CX18_VBI_FRAMES ;
cx - > vbi . sliced_mpeg_size [ idx ] = 0 ;
cx - > vbi . inserted_frame + + ;
2009-11-08 23:45:24 -03:00
cx - > vbi_data_inserted + = mdl - > bytesused ;
2008-04-28 20:24:33 -03:00
}
if ( rc < 0 )
return rc ;
tot_written + = rc ;
if ( tot_written = = tot_count | | single_frame )
break ;
}
return tot_written ;
}
static ssize_t cx18_read_pos ( struct cx18_stream * s , char __user * ubuf ,
size_t count , loff_t * pos , int non_block )
{
ssize_t rc = count ? cx18_read ( s , ubuf , count , non_block ) : 0 ;
struct cx18 * cx = s - > cx ;
CX18_DEBUG_HI_FILE ( " read %zd from %s, got %zd \n " , count , s - > name , rc ) ;
if ( rc > 0 )
2019-02-22 01:37:02 -05:00
* pos + = rc ;
2008-04-28 20:24:33 -03:00
return rc ;
}
int cx18_start_capture ( struct cx18_open_id * id )
{
struct cx18 * cx = id - > cx ;
struct cx18_stream * s = & cx - > streams [ id - > type ] ;
struct cx18_stream * s_vbi ;
2009-12-31 17:19:25 -03:00
struct cx18_stream * s_idx ;
2008-04-28 20:24:33 -03:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_RAD ) {
/* you cannot read from these stream types. */
return - EPERM ;
}
/* Try to claim this stream. */
if ( cx18_claim_stream ( id , s - > type ) )
return - EBUSY ;
/* If capture is already in progress, then we also have to
do nothing extra . */
if ( test_bit ( CX18_F_S_STREAMOFF , & s - > s_flags ) | |
test_and_set_bit ( CX18_F_S_STREAMING , & s - > s_flags ) ) {
set_bit ( CX18_F_S_APPL_IO , & s - > s_flags ) ;
return 0 ;
}
2009-12-31 17:19:25 -03:00
/* Start associated VBI or IDX stream capture if required */
2008-04-28 20:24:33 -03:00
s_vbi = & cx - > streams [ CX18_ENC_STREAM_TYPE_VBI ] ;
2009-12-31 17:19:25 -03:00
s_idx = & cx - > streams [ CX18_ENC_STREAM_TYPE_IDX ] ;
if ( s - > type = = CX18_ENC_STREAM_TYPE_MPG ) {
/*
* The VBI and IDX streams should have been claimed
* automatically , if for internal use , when the MPG stream was
* claimed . We only need to start these streams capturing .
*/
if ( test_bit ( CX18_F_S_INTERNAL_USE , & s_idx - > s_flags ) & &
! test_and_set_bit ( CX18_F_S_STREAMING , & s_idx - > s_flags ) ) {
if ( cx18_start_v4l2_encode_stream ( s_idx ) ) {
CX18_DEBUG_WARN ( " IDX capture start failed \n " ) ;
clear_bit ( CX18_F_S_STREAMING , & s_idx - > s_flags ) ;
goto start_failed ;
}
CX18_DEBUG_INFO ( " IDX capture started \n " ) ;
}
if ( test_bit ( CX18_F_S_INTERNAL_USE , & s_vbi - > s_flags ) & &
! test_and_set_bit ( CX18_F_S_STREAMING , & s_vbi - > s_flags ) ) {
if ( cx18_start_v4l2_encode_stream ( s_vbi ) ) {
CX18_DEBUG_WARN ( " VBI capture start failed \n " ) ;
clear_bit ( CX18_F_S_STREAMING , & s_vbi - > s_flags ) ;
goto start_failed ;
}
CX18_DEBUG_INFO ( " VBI insertion started \n " ) ;
2008-04-28 20:24:33 -03:00
}
}
/* Tell the card to start capturing */
if ( ! cx18_start_v4l2_encode_stream ( s ) ) {
/* We're done */
set_bit ( CX18_F_S_APPL_IO , & s - > s_flags ) ;
/* Resume a possibly paused encoder */
if ( test_and_clear_bit ( CX18_F_I_ENC_PAUSED , & cx - > i_flags ) )
cx18_vapi ( cx , CX18_CPU_CAPTURE_PAUSE , 1 , s - > handle ) ;
return 0 ;
}
2009-12-31 17:19:25 -03:00
start_failed :
2008-04-28 20:24:33 -03:00
CX18_DEBUG_WARN ( " Failed to start capturing for stream %s \n " , s - > name ) ;
2009-12-31 17:19:25 -03:00
/*
* The associated VBI and IDX streams for internal use are released
* automatically when the MPG stream is released . We only need to stop
* the associated stream .
*/
if ( s - > type = = CX18_ENC_STREAM_TYPE_MPG ) {
/* Stop the IDX stream which is always for internal use */
if ( test_bit ( CX18_F_S_STREAMING , & s_idx - > s_flags ) ) {
cx18_stop_v4l2_encode_stream ( s_idx , 0 ) ;
clear_bit ( CX18_F_S_STREAMING , & s_idx - > s_flags ) ;
}
/* Stop the VBI stream, if only running for internal use */
if ( test_bit ( CX18_F_S_STREAMING , & s_vbi - > s_flags ) & &
! test_bit ( CX18_F_S_APPL_IO , & s_vbi - > s_flags ) ) {
cx18_stop_v4l2_encode_stream ( s_vbi , 0 ) ;
clear_bit ( CX18_F_S_STREAMING , & s_vbi - > s_flags ) ;
}
2008-04-28 20:24:33 -03:00
}
clear_bit ( CX18_F_S_STREAMING , & s - > s_flags ) ;
2009-12-31 17:19:25 -03:00
cx18_release_stream ( s ) ; /* Also releases associated streams */
2008-04-28 20:24:33 -03:00
return - EIO ;
}
ssize_t cx18_v4l2_read ( struct file * filp , char __user * buf , size_t count ,
loff_t * pos )
{
2011-03-12 06:35:33 -03:00
struct cx18_open_id * id = file2id ( filp ) ;
2008-04-28 20:24:33 -03:00
struct cx18 * cx = id - > cx ;
struct cx18_stream * s = & cx - > streams [ id - > type ] ;
int rc ;
CX18_DEBUG_HI_FILE ( " read %zd bytes from %s \n " , count , s - > name ) ;
mutex_lock ( & cx - > serialize_lock ) ;
rc = cx18_start_capture ( id ) ;
mutex_unlock ( & cx - > serialize_lock ) ;
if ( rc )
return rc ;
2011-04-06 08:32:56 -03:00
2008-04-28 20:24:33 -03:00
return cx18_read_pos ( s , buf , count , pos , filp - > f_flags & O_NONBLOCK ) ;
}
2017-07-03 03:02:56 -04:00
__poll_t cx18_v4l2_enc_poll ( struct file * filp , poll_table * wait )
2008-04-28 20:24:33 -03:00
{
2017-07-03 03:14:15 -04:00
__poll_t req_events = poll_requested_events ( wait ) ;
2011-03-12 06:35:33 -03:00
struct cx18_open_id * id = file2id ( filp ) ;
2008-04-28 20:24:33 -03:00
struct cx18 * cx = id - > cx ;
struct cx18_stream * s = & cx - > streams [ id - > type ] ;
int eof = test_bit ( CX18_F_S_STREAMOFF , & s - > s_flags ) ;
2017-07-03 03:02:56 -04:00
__poll_t res = 0 ;
2008-04-28 20:24:33 -03:00
/* Start a capture if there is none */
2015-04-02 08:34:29 -03:00
if ( ! eof & & ! test_bit ( CX18_F_S_STREAMING , & s - > s_flags ) & &
2018-02-11 14:34:03 -08:00
( req_events & ( EPOLLIN | EPOLLRDNORM ) ) ) {
2008-04-28 20:24:33 -03:00
int rc ;
mutex_lock ( & cx - > serialize_lock ) ;
rc = cx18_start_capture ( id ) ;
mutex_unlock ( & cx - > serialize_lock ) ;
if ( rc ) {
CX18_DEBUG_INFO ( " Could not start capture for %s (%d) \n " ,
s - > name , rc ) ;
2018-02-11 14:34:03 -08:00
return EPOLLERR ;
2008-04-28 20:24:33 -03:00
}
CX18_DEBUG_FILE ( " Encoder poll started capture \n " ) ;
}
/* add stream's waitq to the poll list */
CX18_DEBUG_HI_FILE ( " Encoder poll \n " ) ;
2015-04-02 08:34:29 -03:00
if ( v4l2_event_pending ( & id - > fh ) )
2018-02-11 14:34:03 -08:00
res | = EPOLLPRI ;
2015-04-02 08:34:29 -03:00
else
poll_wait ( filp , & s - > waitq , wait ) ;
2008-04-28 20:24:33 -03:00
2009-11-04 23:13:58 -03:00
if ( atomic_read ( & s - > q_full . depth ) )
2018-02-11 14:34:03 -08:00
return res | EPOLLIN | EPOLLRDNORM ;
2008-04-28 20:24:33 -03:00
if ( eof )
2018-02-11 14:34:03 -08:00
return res | EPOLLHUP ;
2015-04-02 08:34:29 -03:00
return res ;
2008-04-28 20:24:33 -03:00
}
2017-10-24 11:22:42 -04:00
void cx18_vb_timeout ( struct timer_list * t )
2011-04-06 08:32:56 -03:00
{
2017-10-24 11:22:42 -04:00
struct cx18_stream * s = from_timer ( s , t , vb_timeout ) ;
2011-04-06 08:32:56 -03:00
2023-01-31 11:34:54 +01:00
/*
* Return all of the buffers in error state , so the vbi / vid inode
2011-04-06 08:32:56 -03:00
* can return from blocking .
*/
2023-01-31 11:34:54 +01:00
cx18_clear_queue ( s , VB2_BUF_STATE_ERROR ) ;
2011-04-06 08:32:56 -03:00
}
2023-01-31 11:34:54 +01:00
void cx18_stop_capture ( struct cx18_stream * s , int gop_end )
2008-04-28 20:24:33 -03:00
{
2023-01-31 11:34:54 +01:00
struct cx18 * cx = s - > cx ;
2009-12-31 17:19:25 -03:00
struct cx18_stream * s_vbi = & cx - > streams [ CX18_ENC_STREAM_TYPE_VBI ] ;
struct cx18_stream * s_idx = & cx - > streams [ CX18_ENC_STREAM_TYPE_IDX ] ;
2008-04-28 20:24:33 -03:00
CX18_DEBUG_IOCTL ( " close() of %s \n " , s - > name ) ;
/* 'Unclaim' this stream */
/* Stop capturing */
if ( test_bit ( CX18_F_S_STREAMING , & s - > s_flags ) ) {
CX18_DEBUG_INFO ( " close stopping capture \n " ) ;
2023-01-31 11:34:54 +01:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_MPG ) {
2009-12-31 17:19:25 -03:00
/* Stop internal use associated VBI and IDX streams */
if ( test_bit ( CX18_F_S_STREAMING , & s_vbi - > s_flags ) & &
! test_bit ( CX18_F_S_APPL_IO , & s_vbi - > s_flags ) ) {
[media] cx18: 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 17:44:03 -02:00
CX18_DEBUG_INFO ( " close stopping embedded VBI capture \n " ) ;
2009-12-31 17:19:25 -03:00
cx18_stop_v4l2_encode_stream ( s_vbi , 0 ) ;
}
if ( test_bit ( CX18_F_S_STREAMING , & s_idx - > s_flags ) ) {
CX18_DEBUG_INFO ( " close stopping IDX capture \n " ) ;
cx18_stop_v4l2_encode_stream ( s_idx , 0 ) ;
}
2008-04-28 20:24:33 -03:00
}
2023-01-31 11:34:54 +01:00
if ( s - > type = = CX18_ENC_STREAM_TYPE_VBI & &
2008-04-28 20:24:33 -03:00
test_bit ( CX18_F_S_INTERNAL_USE , & s - > s_flags ) )
/* Also used internally, don't stop capturing */
s - > id = - 1 ;
else
cx18_stop_v4l2_encode_stream ( s , gop_end ) ;
}
if ( ! gop_end ) {
clear_bit ( CX18_F_S_APPL_IO , & s - > s_flags ) ;
clear_bit ( CX18_F_S_STREAMOFF , & s - > s_flags ) ;
cx18_release_stream ( s ) ;
}
}
2008-12-30 06:58:20 -03:00
int cx18_v4l2_close ( struct file * filp )
2008-04-28 20:24:33 -03:00
{
2011-03-12 06:35:33 -03:00
struct v4l2_fh * fh = filp - > private_data ;
struct cx18_open_id * id = fh2id ( fh ) ;
2008-04-28 20:24:33 -03:00
struct cx18 * cx = id - > cx ;
struct cx18_stream * s = & cx - > streams [ id - > type ] ;
2023-01-31 11:34:54 +01:00
struct video_device * vdev = & s - > video_dev ;
2008-04-28 20:24:33 -03:00
CX18_DEBUG_IOCTL ( " close() of %s \n " , s - > name ) ;
mutex_lock ( & cx - > serialize_lock ) ;
2011-10-11 05:23:36 -03:00
/* Stop radio */
if ( id - > type = = CX18_ENC_STREAM_TYPE_RAD & &
2023-01-31 11:34:54 +01:00
v4l2_fh_is_singular_file ( filp ) ) {
2008-04-28 20:24:33 -03:00
/* Closing radio device, return to TV mode */
cx18_mute ( cx ) ;
/* Mark that the radio is no longer in use */
clear_bit ( CX18_F_I_RADIO_USER , & cx - > i_flags ) ;
/* Switch tuner to TV */
2014-04-28 16:53:01 -03:00
cx18_call_all ( cx , video , s_std , cx - > std ) ;
2008-04-28 20:24:33 -03:00
/* Select correct audio input (i.e. TV tuner or Line in) */
cx18_audio_set_io ( cx ) ;
2008-05-25 11:21:27 -03:00
if ( atomic_read ( & cx - > ana_capturing ) > 0 ) {
2008-04-28 20:24:33 -03:00
/* Undo video mute */
cx18_vapi ( cx , CX18_CPU_SET_VIDEO_MUTE , 2 , s - > handle ,
2010-12-31 10:22:52 -03:00
( v4l2_ctrl_g_ctrl ( cx - > cxhdl . video_mute ) |
( v4l2_ctrl_g_ctrl ( cx - > cxhdl . video_mute_yuv ) < < 8 ) ) ) ;
2008-04-28 20:24:33 -03:00
}
/* Done! Unmute and continue. */
cx18_unmute ( cx ) ;
}
2011-10-11 05:23:36 -03:00
2023-01-31 11:34:54 +01:00
if ( id - > type = = CX18_ENC_STREAM_TYPE_YUV & &
filp - > private_data = = vdev - > queue - > owner ) {
vb2_queue_release ( vdev - > queue ) ;
vdev - > queue - > owner = NULL ;
}
2011-10-11 05:23:36 -03:00
v4l2_fh_del ( fh ) ;
v4l2_fh_exit ( fh ) ;
/* 'Unclaim' this stream */
2023-01-31 11:34:54 +01:00
if ( id - > type ! = CX18_ENC_STREAM_TYPE_YUV & & s - > id = = id - > open_id )
cx18_stop_capture ( s , 0 ) ;
2008-04-28 20:24:33 -03:00
kfree ( id ) ;
mutex_unlock ( & cx - > serialize_lock ) ;
return 0 ;
}
static int cx18_serialized_open ( struct cx18_stream * s , struct file * filp )
{
struct cx18 * cx = s - > cx ;
struct cx18_open_id * item ;
CX18_DEBUG_FILE ( " open %s \n " , s - > name ) ;
/* Allocate memory */
2011-03-12 06:35:33 -03:00
item = kzalloc ( sizeof ( struct cx18_open_id ) , GFP_KERNEL ) ;
2008-04-28 20:24:33 -03:00
if ( NULL = = item ) {
CX18_DEBUG_WARN ( " nomem on v4l2 open \n " ) ;
return - ENOMEM ;
}
2015-03-09 13:34:03 -03:00
v4l2_fh_init ( & item - > fh , & s - > video_dev ) ;
2011-03-12 06:35:33 -03:00
2008-04-28 20:24:33 -03:00
item - > cx = cx ;
item - > type = s - > type ;
item - > open_id = cx - > open_id + + ;
2011-03-12 06:35:33 -03:00
filp - > private_data = & item - > fh ;
2011-10-11 05:23:36 -03:00
v4l2_fh_add ( & item - > fh ) ;
2008-04-28 20:24:33 -03:00
2011-10-11 05:23:36 -03:00
if ( item - > type = = CX18_ENC_STREAM_TYPE_RAD & &
v4l2_fh_is_singular_file ( filp ) ) {
2008-04-28 20:24:33 -03:00
if ( ! test_bit ( CX18_F_I_RADIO_USER , & cx - > i_flags ) ) {
2008-05-25 11:21:27 -03:00
if ( atomic_read ( & cx - > ana_capturing ) > 0 ) {
2008-04-28 20:24:33 -03:00
/* switching to radio while capture is
in progress is not polite */
2011-10-11 05:23:36 -03:00
v4l2_fh_del ( & item - > fh ) ;
2011-03-12 06:35:33 -03:00
v4l2_fh_exit ( & item - > fh ) ;
2008-04-28 20:24:33 -03:00
kfree ( item ) ;
return - EBUSY ;
}
}
/* Mark that the radio is being used. */
set_bit ( CX18_F_I_RADIO_USER , & cx - > i_flags ) ;
/* We have the radio */
cx18_mute ( cx ) ;
/* Switch tuner to radio */
2009-02-20 23:52:13 -03:00
cx18_call_all ( cx , tuner , s_radio ) ;
2008-04-28 20:24:33 -03:00
/* Select the correct audio input (i.e. radio tuner) */
cx18_audio_set_io ( cx ) ;
/* Done! Unmute and continue. */
cx18_unmute ( cx ) ;
}
return 0 ;
}
2008-12-30 06:58:20 -03:00
int cx18_v4l2_open ( struct file * filp )
2008-04-28 20:24:33 -03:00
{
2009-02-14 17:08:37 -03:00
int res ;
struct video_device * video_dev = video_devdata ( filp ) ;
struct cx18_stream * s = video_get_drvdata ( video_dev ) ;
2009-07-02 13:52:46 -03:00
struct cx18 * cx = s - > cx ;
2008-04-28 20:24:33 -03:00
mutex_lock ( & cx - > serialize_lock ) ;
if ( cx18_init_on_first_open ( cx ) ) {
2009-12-10 11:47:13 -02:00
CX18_ERR ( " Failed to initialize on %s \n " ,
video_device_node_name ( video_dev ) ) ;
2008-04-28 20:24:33 -03:00
mutex_unlock ( & cx - > serialize_lock ) ;
return - ENXIO ;
}
res = cx18_serialized_open ( s , filp ) ;
mutex_unlock ( & cx - > serialize_lock ) ;
return res ;
}
void cx18_mute ( struct cx18 * cx )
{
2008-08-23 16:42:29 -03:00
u32 h ;
if ( atomic_read ( & cx - > ana_capturing ) ) {
h = cx18_find_handle ( cx ) ;
if ( h ! = CX18_INVALID_TASK_HANDLE )
cx18_vapi ( cx , CX18_CPU_SET_AUDIO_MUTE , 2 , h , 1 ) ;
else
CX18_ERR ( " Can't find valid task handle for mute \n " ) ;
}
2008-04-28 20:24:33 -03:00
CX18_DEBUG_INFO ( " Mute \n " ) ;
}
void cx18_unmute ( struct cx18 * cx )
{
2008-08-23 16:42:29 -03:00
u32 h ;
2008-05-25 11:21:27 -03:00
if ( atomic_read ( & cx - > ana_capturing ) ) {
2008-08-23 16:42:29 -03:00
h = cx18_find_handle ( cx ) ;
if ( h ! = CX18_INVALID_TASK_HANDLE ) {
cx18_msleep_timeout ( 100 , 0 ) ;
cx18_vapi ( cx , CX18_CPU_SET_MISC_PARAMETERS , 2 , h , 12 ) ;
cx18_vapi ( cx , CX18_CPU_SET_AUDIO_MUTE , 2 , h , 0 ) ;
} else
CX18_ERR ( " Can't find valid task handle for unmute \n " ) ;
2008-04-28 20:24:33 -03:00
}
CX18_DEBUG_INFO ( " Unmute \n " ) ;
}