2008-04-29 03:24:33 +04:00
/*
* cx18 ioctl control functions
*
* Derived from ivtv - controls . c
*
* Copyright ( C ) 2007 Hans Verkuil < hverkuil @ xs4all . nl >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA
* 02111 - 1307 USA
*/
# include "cx18-driver.h"
# include "cx18-av-core.h"
# include "cx18-cards.h"
# include "cx18-ioctl.h"
# include "cx18-audio.h"
# include "cx18-i2c.h"
# include "cx18-mailbox.h"
# include "cx18-controls.h"
static const u32 user_ctrls [ ] = {
V4L2_CID_USER_CLASS ,
V4L2_CID_BRIGHTNESS ,
V4L2_CID_CONTRAST ,
V4L2_CID_SATURATION ,
V4L2_CID_HUE ,
V4L2_CID_AUDIO_VOLUME ,
V4L2_CID_AUDIO_BALANCE ,
V4L2_CID_AUDIO_BASS ,
V4L2_CID_AUDIO_TREBLE ,
V4L2_CID_AUDIO_MUTE ,
V4L2_CID_AUDIO_LOUDNESS ,
0
} ;
static const u32 * ctrl_classes [ ] = {
user_ctrls ,
cx2341x_mpeg_ctrls ,
NULL
} ;
2008-06-21 15:36:31 +04:00
int cx18_queryctrl ( struct file * file , void * fh , struct v4l2_queryctrl * qctrl )
2008-04-29 03:24:33 +04:00
{
2008-06-21 15:36:31 +04:00
struct cx18 * cx = ( ( struct cx18_open_id * ) fh ) - > cx ;
2008-04-29 03:24:33 +04:00
const char * name ;
qctrl - > id = v4l2_ctrl_next ( ctrl_classes , qctrl - > id ) ;
if ( qctrl - > id = = 0 )
return - EINVAL ;
switch ( qctrl - > id ) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS :
case V4L2_CID_HUE :
case V4L2_CID_SATURATION :
case V4L2_CID_CONTRAST :
if ( cx18_av_cmd ( cx , VIDIOC_QUERYCTRL , qctrl ) )
qctrl - > flags | = V4L2_CTRL_FLAG_DISABLED ;
return 0 ;
case V4L2_CID_AUDIO_VOLUME :
case V4L2_CID_AUDIO_MUTE :
case V4L2_CID_AUDIO_BALANCE :
case V4L2_CID_AUDIO_BASS :
case V4L2_CID_AUDIO_TREBLE :
case V4L2_CID_AUDIO_LOUDNESS :
if ( cx18_i2c_hw ( cx , cx - > card - > hw_audio_ctrl , VIDIOC_QUERYCTRL , qctrl ) )
qctrl - > flags | = V4L2_CTRL_FLAG_DISABLED ;
return 0 ;
default :
if ( cx2341x_ctrl_query ( & cx - > params , qctrl ) )
qctrl - > flags | = V4L2_CTRL_FLAG_DISABLED ;
return 0 ;
}
strncpy ( qctrl - > name , name , sizeof ( qctrl - > name ) - 1 ) ;
qctrl - > name [ sizeof ( qctrl - > name ) - 1 ] = 0 ;
return 0 ;
}
2008-06-21 15:36:31 +04:00
int cx18_querymenu ( struct file * file , void * fh , struct v4l2_querymenu * qmenu )
2008-04-29 03:24:33 +04:00
{
2008-06-22 19:03:28 +04:00
struct cx18 * cx = ( ( struct cx18_open_id * ) fh ) - > cx ;
2008-04-29 03:24:33 +04:00
struct v4l2_queryctrl qctrl ;
qctrl . id = qmenu - > id ;
2008-06-21 15:36:31 +04:00
cx18_queryctrl ( file , fh , & qctrl ) ;
2008-06-22 19:03:28 +04:00
return v4l2_ctrl_query_menu ( qmenu , & qctrl ,
cx2341x_ctrl_get_menu ( & cx - > params , qmenu - > id ) ) ;
2008-04-29 03:24:33 +04:00
}
2008-06-25 13:32:44 +04:00
static int cx18_try_ctrl ( struct file * file , void * fh ,
struct v4l2_ext_control * vctrl )
2008-04-29 03:24:33 +04:00
{
2008-06-25 13:32:44 +04:00
struct v4l2_queryctrl qctrl ;
const char * * menu_items = NULL ;
int err ;
2008-04-29 03:24:33 +04:00
2008-06-25 13:32:44 +04:00
qctrl . id = vctrl - > id ;
err = cx18_queryctrl ( file , fh , & qctrl ) ;
if ( err )
return err ;
if ( qctrl . type = = V4L2_CTRL_TYPE_MENU )
menu_items = v4l2_ctrl_get_menu ( qctrl . id ) ;
return v4l2_ctrl_check ( vctrl , & qctrl , menu_items ) ;
}
2008-06-21 15:36:31 +04:00
2008-06-25 13:32:44 +04:00
static int cx18_s_ctrl ( struct cx18 * cx , struct v4l2_control * vctrl )
{
2008-04-29 03:24:33 +04:00
switch ( vctrl - > id ) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS :
case V4L2_CID_HUE :
case V4L2_CID_SATURATION :
case V4L2_CID_CONTRAST :
return cx18_av_cmd ( cx , VIDIOC_S_CTRL , vctrl ) ;
case V4L2_CID_AUDIO_VOLUME :
case V4L2_CID_AUDIO_MUTE :
case V4L2_CID_AUDIO_BALANCE :
case V4L2_CID_AUDIO_BASS :
case V4L2_CID_AUDIO_TREBLE :
case V4L2_CID_AUDIO_LOUDNESS :
return cx18_i2c_hw ( cx , cx - > card - > hw_audio_ctrl , VIDIOC_S_CTRL , vctrl ) ;
default :
2008-06-22 18:57:31 +04:00
CX18_DEBUG_IOCTL ( " invalid control 0x%x \n " , vctrl - > id ) ;
2008-04-29 03:24:33 +04:00
return - EINVAL ;
}
return 0 ;
}
2008-06-25 13:32:44 +04:00
static int cx18_g_ctrl ( struct cx18 * cx , struct v4l2_control * vctrl )
2008-04-29 03:24:33 +04:00
{
switch ( vctrl - > id ) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS :
case V4L2_CID_HUE :
case V4L2_CID_SATURATION :
case V4L2_CID_CONTRAST :
return cx18_av_cmd ( cx , VIDIOC_G_CTRL , vctrl ) ;
case V4L2_CID_AUDIO_VOLUME :
case V4L2_CID_AUDIO_MUTE :
case V4L2_CID_AUDIO_BALANCE :
case V4L2_CID_AUDIO_BASS :
case V4L2_CID_AUDIO_TREBLE :
case V4L2_CID_AUDIO_LOUDNESS :
return cx18_i2c_hw ( cx , cx - > card - > hw_audio_ctrl , VIDIOC_G_CTRL , vctrl ) ;
default :
2008-06-22 18:57:31 +04:00
CX18_DEBUG_IOCTL ( " invalid control 0x%x \n " , vctrl - > id ) ;
2008-04-29 03:24:33 +04:00
return - EINVAL ;
}
return 0 ;
}
static int cx18_setup_vbi_fmt ( struct cx18 * cx , enum v4l2_mpeg_stream_vbi_fmt fmt )
{
if ( ! ( cx - > v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE ) )
return - EINVAL ;
2008-05-25 18:21:27 +04:00
if ( atomic_read ( & cx - > ana_capturing ) > 0 )
2008-04-29 03:24:33 +04:00
return - EBUSY ;
/* First try to allocate sliced VBI buffers if needed. */
if ( fmt & & cx - > vbi . sliced_mpeg_data [ 0 ] = = NULL ) {
int i ;
for ( i = 0 ; i < CX18_VBI_FRAMES ; i + + ) {
/* Yuck, hardcoded. Needs to be a define */
cx - > vbi . sliced_mpeg_data [ i ] = kmalloc ( 2049 , GFP_KERNEL ) ;
if ( cx - > vbi . sliced_mpeg_data [ i ] = = NULL ) {
while ( - - i > = 0 ) {
kfree ( cx - > vbi . sliced_mpeg_data [ i ] ) ;
cx - > vbi . sliced_mpeg_data [ i ] = NULL ;
}
return - ENOMEM ;
}
}
}
cx - > vbi . insert_mpeg = fmt ;
if ( cx - > vbi . insert_mpeg = = 0 )
return 0 ;
/* Need sliced data for mpeg insertion */
2008-04-30 04:38:51 +04:00
if ( cx18_get_service_set ( cx - > vbi . sliced_in ) = = 0 ) {
2008-04-29 03:24:33 +04:00
if ( cx - > is_60hz )
cx - > vbi . sliced_in - > service_set = V4L2_SLICED_CAPTION_525 ;
else
cx - > vbi . sliced_in - > service_set = V4L2_SLICED_WSS_625 ;
2008-04-30 04:38:51 +04:00
cx18_expand_service_set ( cx - > vbi . sliced_in , cx - > is_50hz ) ;
2008-04-29 03:24:33 +04:00
}
return 0 ;
}
2008-06-21 15:36:31 +04:00
int cx18_g_ext_ctrls ( struct file * file , void * fh , struct v4l2_ext_controls * c )
2008-04-29 03:24:33 +04:00
{
2008-06-21 15:36:31 +04:00
struct cx18 * cx = ( ( struct cx18_open_id * ) fh ) - > cx ;
2008-04-29 03:24:33 +04:00
struct v4l2_control ctrl ;
2008-06-21 15:36:31 +04:00
if ( c - > ctrl_class = = V4L2_CTRL_CLASS_USER ) {
int i ;
int err = 0 ;
for ( i = 0 ; i < c - > count ; i + + ) {
ctrl . id = c - > controls [ i ] . id ;
ctrl . value = c - > controls [ i ] . value ;
2008-06-25 13:32:44 +04:00
err = cx18_g_ctrl ( cx , & ctrl ) ;
2008-06-21 15:36:31 +04:00
c - > controls [ i ] . value = ctrl . value ;
if ( err ) {
c - > error_idx = i ;
break ;
2008-04-29 03:24:33 +04:00
}
}
2008-06-21 15:36:31 +04:00
return err ;
}
if ( c - > ctrl_class = = V4L2_CTRL_CLASS_MPEG )
return cx2341x_ext_ctrls ( & cx - > params , 0 , c , VIDIOC_G_EXT_CTRLS ) ;
return - EINVAL ;
}
2008-04-29 03:24:33 +04:00
2008-06-21 15:36:31 +04:00
int cx18_s_ext_ctrls ( struct file * file , void * fh , struct v4l2_ext_controls * c )
{
struct cx18_open_id * id = fh ;
struct cx18 * cx = id - > cx ;
int ret ;
struct v4l2_control ctrl ;
2008-04-29 03:24:33 +04:00
2008-06-21 15:36:31 +04:00
ret = v4l2_prio_check ( & cx - > prio , & id - > prio ) ;
if ( ret )
return ret ;
2008-04-29 03:24:33 +04:00
2008-06-21 15:36:31 +04:00
if ( c - > ctrl_class = = V4L2_CTRL_CLASS_USER ) {
int i ;
int err = 0 ;
for ( i = 0 ; i < c - > count ; i + + ) {
ctrl . id = c - > controls [ i ] . id ;
ctrl . value = c - > controls [ i ] . value ;
2008-06-25 13:32:44 +04:00
err = cx18_s_ctrl ( cx , & ctrl ) ;
2008-06-21 15:36:31 +04:00
c - > controls [ i ] . value = ctrl . value ;
if ( err ) {
c - > error_idx = i ;
break ;
2008-04-29 03:24:33 +04:00
}
}
2008-06-21 15:36:31 +04:00
return err ;
2008-04-29 03:24:33 +04:00
}
2008-06-21 15:36:31 +04:00
if ( c - > ctrl_class = = V4L2_CTRL_CLASS_MPEG ) {
struct cx2341x_mpeg_params p = cx - > params ;
int err = cx2341x_ext_ctrls ( & p , atomic_read ( & cx - > ana_capturing ) ,
c , VIDIOC_S_EXT_CTRLS ) ;
2008-04-29 03:24:33 +04:00
2008-06-21 15:36:31 +04:00
if ( err )
2008-04-29 03:24:33 +04:00
return err ;
2008-06-21 15:36:31 +04:00
if ( p . video_encoding ! = cx - > params . video_encoding ) {
int is_mpeg1 = p . video_encoding = =
V4L2_MPEG_VIDEO_ENCODING_MPEG_1 ;
struct v4l2_format fmt ;
/* fix videodecoder resolution */
fmt . type = V4L2_BUF_TYPE_VIDEO_CAPTURE ;
fmt . fmt . pix . width = cx - > params . width
/ ( is_mpeg1 ? 2 : 1 ) ;
fmt . fmt . pix . height = cx - > params . height ;
cx18_av_cmd ( cx , VIDIOC_S_FMT , & fmt ) ;
}
err = cx2341x_update ( cx , cx18_api_func , & cx - > params , & p ) ;
if ( ! err & & cx - > params . stream_vbi_fmt ! = p . stream_vbi_fmt )
err = cx18_setup_vbi_fmt ( cx , p . stream_vbi_fmt ) ;
cx - > params = p ;
cx - > dualwatch_stereo_mode = p . audio_properties & 0x0300 ;
cx18_audio_set_audio_clock_freq ( cx , p . audio_properties & 0x03 ) ;
return err ;
2008-04-29 03:24:33 +04:00
}
2008-06-21 15:36:31 +04:00
return - EINVAL ;
}
2008-04-29 03:24:33 +04:00
2008-06-21 15:36:31 +04:00
int cx18_try_ext_ctrls ( struct file * file , void * fh , struct v4l2_ext_controls * c )
{
struct cx18 * cx = ( ( struct cx18_open_id * ) fh ) - > cx ;
2008-06-25 13:32:44 +04:00
if ( c - > ctrl_class = = V4L2_CTRL_CLASS_USER ) {
int i ;
int err = 0 ;
for ( i = 0 ; i < c - > count ; i + + ) {
err = cx18_try_ctrl ( file , fh , & c - > controls [ i ] ) ;
if ( err ) {
c - > error_idx = i ;
break ;
}
}
return err ;
}
2008-06-21 15:36:31 +04:00
if ( c - > ctrl_class = = V4L2_CTRL_CLASS_MPEG )
return cx2341x_ext_ctrls ( & cx - > params ,
atomic_read ( & cx - > ana_capturing ) ,
c , VIDIOC_TRY_EXT_CTRLS ) ;
return - EINVAL ;
2008-04-29 03:24:33 +04:00
}