2005-04-17 02:20:36 +04:00
/*
mxb - v4l2 driver for the Multimedia eXtension Board
2006-03-17 16:37:02 +03:00
2006-03-14 08:20:41 +03:00
Copyright ( C ) 1998 - 2006 Michael Hunold < michael @ mihu . de >
2005-04-17 02:20:36 +04:00
Visit http : //www.mihu.de/linux/saa7146/mxb/
for further details about this card .
2006-03-17 16:37:02 +03:00
2005-04-17 02:20:36 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU 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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# define DEBUG_VARIABLE debug
# include <media/saa7146_vv.h>
# include <media/tuner.h>
2006-01-09 20:32:31 +03:00
# include <media/v4l2-common.h>
2008-09-06 22:40:25 +04:00
# include <media/saa7115.h>
2005-04-17 02:20:36 +04:00
# include "mxb.h"
# include "tea6415c.h"
# include "tea6420.h"
2009-02-07 17:18:05 +03:00
# define I2C_SAA5246A 0x11
# define I2C_SAA7111A 0x24
# define I2C_TDA9840 0x42
# define I2C_TEA6415C 0x43
# define I2C_TEA6420_1 0x4c
# define I2C_TEA6420_2 0x4d
# define I2C_TUNER 0x60
2005-04-17 02:20:36 +04:00
2006-03-17 16:37:02 +03:00
# define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
2005-04-17 02:20:36 +04:00
/* global variable */
2008-04-22 21:41:48 +04:00
static int mxb_num ;
2005-04-17 02:20:36 +04:00
2006-03-17 16:37:02 +03:00
/* initial frequence the tuner will be tuned to.
2005-04-17 02:20:36 +04:00
in verden ( lower saxony , germany ) 4148 is a
channel called " phoenix " */
static int freq = 4148 ;
module_param ( freq , int , 0644 ) ;
MODULE_PARM_DESC ( freq , " initial frequency the tuner will be tuned to while setup " ) ;
2008-04-22 21:41:48 +04:00
static int debug ;
2005-04-17 02:20:36 +04:00
module_param ( debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Turn on/off device debugging (default:off). " ) ;
# define MXB_INPUTS 4
enum { TUNER , AUX1 , AUX3 , AUX3_YC } ;
static struct v4l2_input mxb_inputs [ MXB_INPUTS ] = {
2006-03-17 16:37:02 +03:00
{ TUNER , " Tuner " , V4L2_INPUT_TYPE_TUNER , 1 , 0 , V4L2_STD_PAL_BG | V4L2_STD_NTSC_M , 0 } ,
2005-04-17 02:20:36 +04:00
{ AUX1 , " AUX1 " , V4L2_INPUT_TYPE_CAMERA , 2 , 0 , V4L2_STD_PAL_BG | V4L2_STD_NTSC_M , 0 } ,
{ AUX3 , " AUX3 Composite " , V4L2_INPUT_TYPE_CAMERA , 4 , 0 , V4L2_STD_PAL_BG | V4L2_STD_NTSC_M , 0 } ,
{ AUX3_YC , " AUX3 S-Video " , V4L2_INPUT_TYPE_CAMERA , 4 , 0 , V4L2_STD_PAL_BG | V4L2_STD_NTSC_M , 0 } ,
} ;
/* this array holds the information, which port of the saa7146 each
input actually uses . the mxb uses port 0 for every input */
static struct {
int hps_source ;
int hps_sync ;
2006-03-17 16:37:02 +03:00
} input_port_selection [ MXB_INPUTS ] = {
2005-04-17 02:20:36 +04:00
{ SAA7146_HPS_SOURCE_PORT_A , SAA7146_HPS_SYNC_PORT_A } ,
{ SAA7146_HPS_SOURCE_PORT_A , SAA7146_HPS_SYNC_PORT_A } ,
{ SAA7146_HPS_SOURCE_PORT_A , SAA7146_HPS_SYNC_PORT_A } ,
{ SAA7146_HPS_SOURCE_PORT_A , SAA7146_HPS_SYNC_PORT_A } ,
} ;
/* this array holds the information of the audio source (mxb_audios),
which has to be switched corresponding to the video source ( mxb_channels ) */
static int video_audio_connect [ MXB_INPUTS ] =
{ 0 , 1 , 3 , 3 } ;
2009-04-02 18:26:22 +04:00
struct mxb_routing {
u32 input ;
u32 output ;
} ;
2009-02-07 17:18:05 +03:00
/* These are the necessary input-output-pins for bringing one audio source
( see above ) to the CD - output . Note that gain is set to 0 in this table . */
2009-04-02 18:26:22 +04:00
static struct mxb_routing TEA6420_cd [ MXB_AUDIOS + 1 ] [ 2 ] = {
2009-02-07 17:18:05 +03:00
{ { 1 , 1 } , { 1 , 1 } } , /* Tuner */
{ { 5 , 1 } , { 6 , 1 } } , /* AUX 1 */
{ { 4 , 1 } , { 6 , 1 } } , /* AUX 2 */
{ { 3 , 1 } , { 6 , 1 } } , /* AUX 3 */
{ { 1 , 1 } , { 3 , 1 } } , /* Radio */
{ { 1 , 1 } , { 2 , 1 } } , /* CD-Rom */
{ { 6 , 1 } , { 6 , 1 } } /* Mute */
} ;
/* These are the necessary input-output-pins for bringing one audio source
( see above ) to the line - output . Note that gain is set to 0 in this table . */
2009-04-02 18:26:22 +04:00
static struct mxb_routing TEA6420_line [ MXB_AUDIOS + 1 ] [ 2 ] = {
2009-02-07 17:18:05 +03:00
{ { 2 , 3 } , { 1 , 2 } } ,
{ { 5 , 3 } , { 6 , 2 } } ,
{ { 4 , 3 } , { 6 , 2 } } ,
{ { 3 , 3 } , { 6 , 2 } } ,
{ { 2 , 3 } , { 3 , 2 } } ,
{ { 2 , 3 } , { 2 , 2 } } ,
{ { 6 , 3 } , { 6 , 2 } } /* Mute */
} ;
2005-04-17 02:20:36 +04:00
# define MAXCONTROLS 1
static struct v4l2_queryctrl mxb_controls [ ] = {
{ V4L2_CID_AUDIO_MUTE , V4L2_CTRL_TYPE_BOOLEAN , " Mute " , 0 , 1 , 1 , 0 , 0 } ,
} ;
struct mxb
{
struct video_device * video_dev ;
struct video_device * vbi_dev ;
2006-03-17 16:37:02 +03:00
struct i2c_adapter i2c_adapter ;
2005-04-17 02:20:36 +04:00
2009-02-07 17:18:05 +03:00
struct v4l2_subdev * saa7111a ;
struct v4l2_subdev * tda9840 ;
struct v4l2_subdev * tea6415c ;
struct v4l2_subdev * tuner ;
struct v4l2_subdev * tea6420_1 ;
struct v4l2_subdev * tea6420_2 ;
2005-04-17 02:20:36 +04:00
int cur_mode ; /* current audio mode (mono, stereo, ...) */
int cur_input ; /* current input */
int cur_mute ; /* current mute status */
2005-07-27 22:46:00 +04:00
struct v4l2_frequency cur_freq ; /* current frequency the tuner is tuned to */
2005-04-17 02:20:36 +04:00
} ;
2009-02-07 17:18:05 +03:00
# define saa7111a_call(mxb, o, f, args...) \
v4l2_subdev_call ( mxb - > saa7111a , o , f , # # args )
# define tda9840_call(mxb, o, f, args...) \
v4l2_subdev_call ( mxb - > tda9840 , o , f , # # args )
# define tea6415c_call(mxb, o, f, args...) \
v4l2_subdev_call ( mxb - > tea6415c , o , f , # # args )
# define tuner_call(mxb, o, f, args...) \
v4l2_subdev_call ( mxb - > tuner , o , f , # # args )
# define call_all(dev, o, f, args...) \
v4l2_device_call_until_err ( & dev - > v4l2_dev , 0 , o , f , # # args )
2008-01-27 20:14:51 +03:00
2009-04-02 18:26:22 +04:00
static inline void tea6420_route_cd ( struct mxb * mxb , int idx )
{
v4l2_subdev_call ( mxb - > tea6420_1 , audio , s_routing ,
TEA6420_cd [ idx ] [ 0 ] . input , TEA6420_cd [ idx ] [ 0 ] . output , 0 ) ;
v4l2_subdev_call ( mxb - > tea6420_2 , audio , s_routing ,
TEA6420_cd [ idx ] [ 1 ] . input , TEA6420_cd [ idx ] [ 1 ] . output , 0 ) ;
}
static inline void tea6420_route_line ( struct mxb * mxb , int idx )
{
v4l2_subdev_call ( mxb - > tea6420_1 , audio , s_routing ,
TEA6420_line [ idx ] [ 0 ] . input , TEA6420_line [ idx ] [ 0 ] . output , 0 ) ;
v4l2_subdev_call ( mxb - > tea6420_2 , audio , s_routing ,
TEA6420_line [ idx ] [ 1 ] . input , TEA6420_line [ idx ] [ 1 ] . output , 0 ) ;
}
2009-02-07 17:18:05 +03:00
static struct saa7146_extension extension ;
2008-01-27 20:14:51 +03:00
2009-02-07 17:18:05 +03:00
static int mxb_probe ( struct saa7146_dev * dev )
2005-04-17 02:20:36 +04:00
{
2009-02-07 17:18:05 +03:00
struct mxb * mxb = NULL ;
2010-02-20 13:56:25 +03:00
int err ;
2005-04-17 02:20:36 +04:00
2010-02-20 13:56:25 +03:00
err = saa7146_vv_devinit ( dev ) ;
if ( err )
return err ;
2006-01-12 00:40:56 +03:00
mxb = kzalloc ( sizeof ( struct mxb ) , GFP_KERNEL ) ;
2009-02-07 17:18:05 +03:00
if ( mxb = = NULL ) {
2005-04-17 02:20:36 +04:00
DEB_D ( ( " not enough kernel memory. \n " ) ) ;
return - ENOMEM ;
}
2008-09-07 15:32:44 +04:00
snprintf ( mxb - > i2c_adapter . name , sizeof ( mxb - > i2c_adapter . name ) , " mxb%d " , mxb_num ) ;
2005-04-17 02:20:36 +04:00
saa7146_i2c_adapter_prepare ( dev , & mxb - > i2c_adapter , SAA7146_I2C_BUS_BIT_RATE_480 ) ;
2009-02-07 17:18:05 +03:00
if ( i2c_add_adapter ( & mxb - > i2c_adapter ) < 0 ) {
2005-04-17 02:20:36 +04:00
DEB_S ( ( " cannot register i2c-device. skipping. \n " ) ) ;
kfree ( mxb ) ;
return - EFAULT ;
}
2009-04-01 10:57:53 +04:00
mxb - > saa7111a = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" saa7115 " , " saa7111 " , I2C_SAA7111A , NULL ) ;
2009-04-01 10:57:53 +04:00
mxb - > tea6420_1 = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" tea6420 " , " tea6420 " , I2C_TEA6420_1 , NULL ) ;
2009-04-01 10:57:53 +04:00
mxb - > tea6420_2 = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" tea6420 " , " tea6420 " , I2C_TEA6420_2 , NULL ) ;
2009-04-01 10:57:53 +04:00
mxb - > tea6415c = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" tea6415c " , " tea6415c " , I2C_TEA6415C , NULL ) ;
2009-04-01 10:57:53 +04:00
mxb - > tda9840 = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" tda9840 " , " tda9840 " , I2C_TDA9840 , NULL ) ;
2009-04-01 10:57:53 +04:00
mxb - > tuner = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" tuner " , " tuner " , I2C_TUNER , NULL ) ;
2009-04-01 10:57:53 +04:00
if ( v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & mxb - > i2c_adapter ,
2009-08-10 09:49:08 +04:00
" saa5246a " , " saa5246a " , I2C_SAA5246A , NULL ) ) {
2009-02-07 17:18:05 +03:00
printk ( KERN_INFO " mxb: found teletext decoder \n " ) ;
}
2005-04-17 02:20:36 +04:00
/* check if all devices are present */
2008-03-29 06:07:38 +03:00
if ( ! mxb - > tea6420_1 | | ! mxb - > tea6420_2 | | ! mxb - > tea6415c | |
! mxb - > tda9840 | | ! mxb - > saa7111a | | ! mxb - > tuner ) {
2005-04-17 02:20:36 +04:00
printk ( " mxb: did not find all i2c devices. aborting \n " ) ;
i2c_del_adapter ( & mxb - > i2c_adapter ) ;
kfree ( mxb ) ;
return - ENODEV ;
}
2006-03-17 16:37:02 +03:00
/* all devices are present, probe was successful */
2005-04-17 02:20:36 +04:00
/* we store the pointer in our private data field */
dev - > ext_priv = mxb ;
return 0 ;
}
2006-03-17 16:37:02 +03:00
/* some init data for the saa7740, the so-called 'sound arena module'.
2005-04-17 02:20:36 +04:00
there are no specs available , so we simply use some init values */
static struct {
int length ;
char data [ 9 ] ;
} mxb_saa7740_init [ ] = {
{ 3 , { 0x80 , 0x00 , 0x00 } } , { 3 , { 0x80 , 0x89 , 0x00 } } ,
{ 3 , { 0x80 , 0xb0 , 0x0a } } , { 3 , { 0x00 , 0x00 , 0x00 } } ,
{ 3 , { 0x49 , 0x00 , 0x00 } } , { 3 , { 0x4a , 0x00 , 0x00 } } ,
{ 3 , { 0x4b , 0x00 , 0x00 } } , { 3 , { 0x4c , 0x00 , 0x00 } } ,
{ 3 , { 0x4d , 0x00 , 0x00 } } , { 3 , { 0x4e , 0x00 , 0x00 } } ,
{ 3 , { 0x4f , 0x00 , 0x00 } } , { 3 , { 0x50 , 0x00 , 0x00 } } ,
{ 3 , { 0x51 , 0x00 , 0x00 } } , { 3 , { 0x52 , 0x00 , 0x00 } } ,
{ 3 , { 0x53 , 0x00 , 0x00 } } , { 3 , { 0x54 , 0x00 , 0x00 } } ,
{ 3 , { 0x55 , 0x00 , 0x00 } } , { 3 , { 0x56 , 0x00 , 0x00 } } ,
{ 3 , { 0x57 , 0x00 , 0x00 } } , { 3 , { 0x58 , 0x00 , 0x00 } } ,
{ 3 , { 0x59 , 0x00 , 0x00 } } , { 3 , { 0x5a , 0x00 , 0x00 } } ,
{ 3 , { 0x5b , 0x00 , 0x00 } } , { 3 , { 0x5c , 0x00 , 0x00 } } ,
{ 3 , { 0x5d , 0x00 , 0x00 } } , { 3 , { 0x5e , 0x00 , 0x00 } } ,
{ 3 , { 0x5f , 0x00 , 0x00 } } , { 3 , { 0x60 , 0x00 , 0x00 } } ,
{ 3 , { 0x61 , 0x00 , 0x00 } } , { 3 , { 0x62 , 0x00 , 0x00 } } ,
{ 3 , { 0x63 , 0x00 , 0x00 } } , { 3 , { 0x64 , 0x00 , 0x00 } } ,
{ 3 , { 0x65 , 0x00 , 0x00 } } , { 3 , { 0x66 , 0x00 , 0x00 } } ,
{ 3 , { 0x67 , 0x00 , 0x00 } } , { 3 , { 0x68 , 0x00 , 0x00 } } ,
{ 3 , { 0x69 , 0x00 , 0x00 } } , { 3 , { 0x6a , 0x00 , 0x00 } } ,
{ 3 , { 0x6b , 0x00 , 0x00 } } , { 3 , { 0x6c , 0x00 , 0x00 } } ,
{ 3 , { 0x6d , 0x00 , 0x00 } } , { 3 , { 0x6e , 0x00 , 0x00 } } ,
{ 3 , { 0x6f , 0x00 , 0x00 } } , { 3 , { 0x70 , 0x00 , 0x00 } } ,
{ 3 , { 0x71 , 0x00 , 0x00 } } , { 3 , { 0x72 , 0x00 , 0x00 } } ,
{ 3 , { 0x73 , 0x00 , 0x00 } } , { 3 , { 0x74 , 0x00 , 0x00 } } ,
{ 3 , { 0x75 , 0x00 , 0x00 } } , { 3 , { 0x76 , 0x00 , 0x00 } } ,
{ 3 , { 0x77 , 0x00 , 0x00 } } , { 3 , { 0x41 , 0x00 , 0x42 } } ,
{ 3 , { 0x42 , 0x10 , 0x42 } } , { 3 , { 0x43 , 0x20 , 0x42 } } ,
{ 3 , { 0x44 , 0x30 , 0x42 } } , { 3 , { 0x45 , 0x00 , 0x01 } } ,
{ 3 , { 0x46 , 0x00 , 0x01 } } , { 3 , { 0x47 , 0x00 , 0x01 } } ,
{ 3 , { 0x48 , 0x00 , 0x01 } } ,
{ 9 , { 0x01 , 0x03 , 0xc5 , 0x5c , 0x7a , 0x85 , 0x01 , 0x00 , 0x54 } } ,
{ 9 , { 0x21 , 0x03 , 0xc5 , 0x5c , 0x7a , 0x85 , 0x01 , 0x00 , 0x54 } } ,
{ 9 , { 0x09 , 0x0b , 0xb4 , 0x6b , 0x74 , 0x85 , 0x95 , 0x00 , 0x34 } } ,
{ 9 , { 0x29 , 0x0b , 0xb4 , 0x6b , 0x74 , 0x85 , 0x95 , 0x00 , 0x34 } } ,
{ 9 , { 0x11 , 0x17 , 0x43 , 0x62 , 0x68 , 0x89 , 0xd1 , 0xff , 0xb0 } } ,
{ 9 , { 0x31 , 0x17 , 0x43 , 0x62 , 0x68 , 0x89 , 0xd1 , 0xff , 0xb0 } } ,
{ 9 , { 0x19 , 0x20 , 0x62 , 0x51 , 0x5a , 0x95 , 0x19 , 0x01 , 0x50 } } ,
{ 9 , { 0x39 , 0x20 , 0x62 , 0x51 , 0x5a , 0x95 , 0x19 , 0x01 , 0x50 } } ,
{ 9 , { 0x05 , 0x3e , 0xd2 , 0x69 , 0x4e , 0x9a , 0x51 , 0x00 , 0xf0 } } ,
{ 9 , { 0x25 , 0x3e , 0xd2 , 0x69 , 0x4e , 0x9a , 0x51 , 0x00 , 0xf0 } } ,
{ 9 , { 0x0d , 0x3d , 0xa1 , 0x40 , 0x7d , 0x9f , 0x29 , 0xfe , 0x14 } } ,
{ 9 , { 0x2d , 0x3d , 0xa1 , 0x40 , 0x7d , 0x9f , 0x29 , 0xfe , 0x14 } } ,
{ 9 , { 0x15 , 0x73 , 0xa1 , 0x50 , 0x5d , 0xa6 , 0xf5 , 0xfe , 0x38 } } ,
{ 9 , { 0x35 , 0x73 , 0xa1 , 0x50 , 0x5d , 0xa6 , 0xf5 , 0xfe , 0x38 } } ,
{ 9 , { 0x1d , 0xed , 0xd0 , 0x68 , 0x29 , 0xb4 , 0xe1 , 0x00 , 0xb8 } } ,
{ 9 , { 0x3d , 0xed , 0xd0 , 0x68 , 0x29 , 0xb4 , 0xe1 , 0x00 , 0xb8 } } ,
{ 3 , { 0x80 , 0xb3 , 0x0a } } ,
2008-09-07 00:24:30 +04:00
{ - 1 , { 0 } }
2005-04-17 02:20:36 +04:00
} ;
/* bring hardware to a sane state. this has to be done, just in case someone
wants to capture from this device before it has been properly initialized .
the capture engine would badly fail , because no valid signal arrives on the
saa7146 , thus leading to timeouts and stuff . */
static int mxb_init_done ( struct saa7146_dev * dev )
{
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
struct i2c_msg msg ;
2005-07-13 00:58:59 +04:00
struct tuner_setup tun_setup ;
2006-03-14 08:20:41 +03:00
v4l2_std_id std = V4L2_STD_PAL_BG ;
2005-04-17 02:20:36 +04:00
int i = 0 , err = 0 ;
/* select video mode in saa7111a */
2009-04-01 10:52:39 +04:00
saa7111a_call ( mxb , core , s_std , std ) ;
2005-04-17 02:20:36 +04:00
/* select tuner-output on saa7111a */
i = 0 ;
2009-04-02 18:26:22 +04:00
saa7111a_call ( mxb , video , s_routing , SAA7115_COMPOSITE0 ,
SAA7111_FMT_CCIR | SAA7111_VBI_BYPASS , 0 ) ;
2005-04-17 02:20:36 +04:00
/* select a tuner type */
2005-07-13 00:58:59 +04:00
tun_setup . mode_mask = T_ANALOG_TV ;
tun_setup . addr = ADDR_UNSET ;
2005-07-27 22:46:00 +04:00
tun_setup . type = TUNER_PHILIPS_PAL ;
2009-02-07 17:18:05 +03:00
tuner_call ( mxb , tuner , s_type_addr , & tun_setup ) ;
2005-07-27 22:46:00 +04:00
/* tune in some frequency on tuner */
mxb - > cur_freq . tuner = 0 ;
mxb - > cur_freq . type = V4L2_TUNER_ANALOG_TV ;
mxb - > cur_freq . frequency = freq ;
2009-02-07 17:18:05 +03:00
tuner_call ( mxb , tuner , s_frequency , & mxb - > cur_freq ) ;
2005-07-27 22:46:00 +04:00
2006-03-14 08:20:41 +03:00
/* set a default video standard */
2009-04-01 10:52:39 +04:00
tuner_call ( mxb , core , s_std , std ) ;
2006-03-14 08:20:41 +03:00
2005-04-17 02:20:36 +04:00
/* mute audio on tea6420s */
2009-04-02 18:26:22 +04:00
tea6420_route_line ( mxb , 6 ) ;
tea6420_route_cd ( mxb , 6 ) ;
2005-04-17 02:20:36 +04:00
2009-02-07 17:18:05 +03:00
/* switch to tuner-channel on tea6415c */
2009-04-02 18:26:22 +04:00
tea6415c_call ( mxb , video , s_routing , 3 , 17 , 0 ) ;
2005-04-17 02:20:36 +04:00
2009-02-07 17:18:05 +03:00
/* select tuner-output on multicable on tea6415c */
2009-04-02 18:26:22 +04:00
tea6415c_call ( mxb , video , s_routing , 3 , 13 , 0 ) ;
2006-03-17 16:37:02 +03:00
2005-04-17 02:20:36 +04:00
/* the rest for mxb */
mxb - > cur_input = 0 ;
mxb - > cur_mute = 1 ;
mxb - > cur_mode = V4L2_TUNER_MODE_STEREO ;
2006-03-17 16:37:02 +03:00
2005-04-17 02:20:36 +04:00
/* check if the saa7740 (aka 'sound arena module') is present
2006-03-17 16:37:02 +03:00
on the mxb . if so , we must initialize it . due to lack of
2005-04-17 02:20:36 +04:00
informations about the saa7740 , the values were reverse
engineered . */
msg . addr = 0x1b ;
msg . flags = 0 ;
msg . len = mxb_saa7740_init [ 0 ] . length ;
msg . buf = & mxb_saa7740_init [ 0 ] . data [ 0 ] ;
2008-09-07 00:24:30 +04:00
err = i2c_transfer ( & mxb - > i2c_adapter , & msg , 1 ) ;
if ( err = = 1 ) {
2005-04-17 02:20:36 +04:00
/* the sound arena module is a pos, that's probably the reason
philips refuses to hand out a datasheet for the saa7740 . . .
it seems to screw up the i2c bus , so we disable fast irq
based i2c transactions here and rely on the slow and safe
polling method . . . */
extension . flags & = ~ SAA7146_USE_I2C_IRQ ;
2008-09-07 00:24:30 +04:00
for ( i = 1 ; ; i + + ) {
if ( - 1 = = mxb_saa7740_init [ i ] . length )
2005-04-17 02:20:36 +04:00
break ;
2006-03-17 16:37:02 +03:00
msg . len = mxb_saa7740_init [ i ] . length ;
2005-04-17 02:20:36 +04:00
msg . buf = & mxb_saa7740_init [ i ] . data [ 0 ] ;
2008-09-07 00:24:30 +04:00
err = i2c_transfer ( & mxb - > i2c_adapter , & msg , 1 ) ;
if ( err ! = 1 ) {
2005-04-17 02:20:36 +04:00
DEB_D ( ( " failed to initialize 'sound arena module'. \n " ) ) ;
goto err ;
}
}
INFO ( ( " 'sound arena module' detected. \n " ) ) ;
}
2006-03-17 16:37:02 +03:00
err :
2005-04-17 02:20:36 +04:00
/* the rest for saa7146: you should definitely set some basic values
for the input - port handling of the saa7146 . */
/* ext->saa has been filled by the core driver */
2006-03-17 16:37:02 +03:00
2005-04-17 02:20:36 +04:00
/* some stuff is done via variables */
2008-09-07 00:24:30 +04:00
saa7146_set_hps_source_and_sync ( dev , input_port_selection [ mxb - > cur_input ] . hps_source ,
input_port_selection [ mxb - > cur_input ] . hps_sync ) ;
2005-04-17 02:20:36 +04:00
/* some stuff is done via direct write to the registers */
/* this is ugly, but because of the fact that this is completely
hardware dependend , it should be done directly . . . */
2006-03-17 16:37:02 +03:00
saa7146_write ( dev , DD1_STREAM_B , 0x00000000 ) ;
2005-04-17 02:20:36 +04:00
saa7146_write ( dev , DD1_INIT , 0x02000200 ) ;
saa7146_write ( dev , MC2 , ( MASK_09 | MASK_25 | MASK_10 | MASK_26 ) ) ;
return 0 ;
}
/* interrupt-handler. this gets called when irq_mask is != 0.
it must clear the interrupt - bits in irq_mask it has handled */
/*
void mxb_irq_bh ( struct saa7146_dev * dev , u32 * irq_mask )
{
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
}
*/
2009-01-19 01:59:11 +03:00
static int vidioc_queryctrl ( struct file * file , void * fh , struct v4l2_queryctrl * qc )
2005-04-17 02:20:36 +04:00
{
2009-01-19 01:59:11 +03:00
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
int i ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
for ( i = MAXCONTROLS - 1 ; i > = 0 ; i - - ) {
if ( mxb_controls [ i ] . id = = qc - > id ) {
* qc = mxb_controls [ i ] ;
DEB_D ( ( " VIDIOC_QUERYCTRL %d. \n " , qc - > id ) ) ;
return 0 ;
}
}
return dev - > ext_vv_data - > core_ops - > vidioc_queryctrl ( file , fh , qc ) ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_g_ctrl ( struct file * file , void * fh , struct v4l2_control * vc )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
int i ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
for ( i = MAXCONTROLS - 1 ; i > = 0 ; i - - ) {
if ( mxb_controls [ i ] . id = = vc - > id )
break ;
2005-04-17 02:20:36 +04:00
}
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
if ( i < 0 )
return dev - > ext_vv_data - > core_ops - > vidioc_g_ctrl ( file , fh , vc ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
if ( vc - > id = = V4L2_CID_AUDIO_MUTE ) {
vc - > value = mxb - > cur_mute ;
DEB_D ( ( " VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d. \n " , vc - > value ) ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d. \n " , vc - > value ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-19 01:59:11 +03:00
static int vidioc_s_ctrl ( struct file * file , void * fh , struct v4l2_control * vc )
2005-04-17 02:20:36 +04:00
{
2009-01-19 01:59:11 +03:00
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
2008-09-07 00:24:30 +04:00
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2009-01-19 01:59:11 +03:00
int i = 0 ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
for ( i = MAXCONTROLS - 1 ; i > = 0 ; i - - ) {
if ( mxb_controls [ i ] . id = = vc - > id )
break ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
if ( i < 0 )
return dev - > ext_vv_data - > core_ops - > vidioc_s_ctrl ( file , fh , vc ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
if ( vc - > id = = V4L2_CID_AUDIO_MUTE ) {
mxb - > cur_mute = vc - > value ;
2009-04-02 18:26:22 +04:00
/* switch the audio-source */
tea6420_route_line ( mxb , vc - > value ? 6 :
video_audio_connect [ mxb - > cur_input ] ) ;
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_S_CTRL, V4L2_CID_AUDIO_MUTE: %d. \n " , vc - > value ) ) ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_enum_input ( struct file * file , void * fh , struct v4l2_input * i )
{
DEB_EE ( ( " VIDIOC_ENUMINPUT %d. \n " , i - > index ) ) ;
2009-05-02 23:38:47 +04:00
if ( i - > index > = MXB_INPUTS )
2009-01-19 01:59:11 +03:00
return - EINVAL ;
memcpy ( i , & mxb_inputs [ i - > index ] , sizeof ( struct v4l2_input ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-19 01:59:11 +03:00
static int vidioc_g_input ( struct file * file , void * fh , unsigned int * i )
2005-04-17 02:20:36 +04:00
{
2009-01-19 01:59:11 +03:00
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
2008-09-07 00:24:30 +04:00
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2009-01-19 01:59:11 +03:00
* i = mxb - > cur_input ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_G_INPUT %d. \n " , * i ) ) ;
return 0 ;
}
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
static int vidioc_s_input ( struct file * file , void * fh , unsigned int input )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2009-04-02 18:26:22 +04:00
int err = 0 ;
2009-01-19 01:59:11 +03:00
int i = 0 ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_S_INPUT %d. \n " , input ) ) ;
2006-03-17 16:37:02 +03:00
2009-10-23 14:59:42 +04:00
if ( input > = MXB_INPUTS )
2009-01-19 01:59:11 +03:00
return - EINVAL ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
mxb - > cur_input = input ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
saa7146_set_hps_source_and_sync ( dev , input_port_selection [ input ] . hps_source ,
input_port_selection [ input ] . hps_sync ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
/* prepare switching of tea6415c and saa7111a;
have a look at the ' background ' - file for further informations */
switch ( input ) {
case TUNER :
i = SAA7115_COMPOSITE0 ;
2006-03-17 16:37:02 +03:00
2009-04-02 18:26:22 +04:00
err = tea6415c_call ( mxb , video , s_routing , 3 , 17 , 0 ) ;
2009-01-19 01:59:11 +03:00
/* connect tuner-output always to multicable */
2009-04-02 18:26:22 +04:00
if ( ! err )
err = tea6415c_call ( mxb , video , s_routing , 3 , 13 , 0 ) ;
2009-01-19 01:59:11 +03:00
break ;
case AUX3_YC :
/* nothing to be done here. aux3_yc is
directly connected to the saa711a */
i = SAA7115_SVIDEO1 ;
break ;
case AUX3 :
/* nothing to be done here. aux3 is
directly connected to the saa711a */
i = SAA7115_COMPOSITE1 ;
break ;
case AUX1 :
i = SAA7115_COMPOSITE0 ;
2009-04-02 18:26:22 +04:00
err = tea6415c_call ( mxb , video , s_routing , 1 , 17 , 0 ) ;
2009-01-19 01:59:11 +03:00
break ;
}
2006-03-17 16:37:02 +03:00
2009-04-02 18:26:22 +04:00
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
/* switch video in saa7111a */
2009-04-02 18:26:22 +04:00
if ( saa7111a_call ( mxb , video , s_routing , i , 0 , 0 ) )
2009-01-19 01:59:11 +03:00
printk ( KERN_ERR " VIDIOC_S_INPUT: could not address saa7111a #1. \n " ) ;
/* switch the audio-source only if necessary */
2009-04-02 18:26:22 +04:00
if ( 0 = = mxb - > cur_mute )
tea6420_route_line ( mxb , video_audio_connect [ input ] ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_g_tuner ( struct file * file , void * fh , struct v4l2_tuner * t )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
if ( t - > index ) {
DEB_D ( ( " VIDIOC_G_TUNER: channel %d does not have a tuner attached. \n " , t - > index ) ) ;
return - EINVAL ;
}
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_G_TUNER: %d \n " , t - > index ) ) ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
memset ( t , 0 , sizeof ( * t ) ) ;
strlcpy ( t - > name , " TV Tuner " , sizeof ( t - > name ) ) ;
t - > type = V4L2_TUNER_ANALOG_TV ;
t - > capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP ;
t - > audmode = mxb - > cur_mode ;
2009-02-07 17:18:05 +03:00
return call_all ( dev , tuner , g_tuner , t ) ;
2009-01-19 01:59:11 +03:00
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_s_tuner ( struct file * file , void * fh , struct v4l2_tuner * t )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
if ( t - > index ) {
DEB_D ( ( " VIDIOC_S_TUNER: channel %d does not have a tuner attached. \n " , t - > index ) ) ;
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
mxb - > cur_mode = t - > audmode ;
2009-02-07 17:18:05 +03:00
return call_all ( dev , tuner , s_tuner , t ) ;
2009-01-19 01:59:11 +03:00
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_g_frequency ( struct file * file , void * fh , struct v4l2_frequency * f )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
if ( mxb - > cur_input ) {
DEB_D ( ( " VIDIOC_G_FREQ: channel %d does not have a tuner! \n " ,
mxb - > cur_input ) ) ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2009-01-19 01:59:11 +03:00
* f = mxb - > cur_freq ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_G_FREQ: freq:0x%08x. \n " , mxb - > cur_freq . frequency ) ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_s_frequency ( struct file * file , void * fh , struct v4l2_frequency * f )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
struct saa7146_vv * vv = dev - > vv_data ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
if ( f - > tuner )
return - EINVAL ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
if ( V4L2_TUNER_ANALOG_TV ! = f - > type )
return - EINVAL ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
if ( mxb - > cur_input ) {
DEB_D ( ( " VIDIOC_S_FREQ: channel %d does not have a tuner! \n " , mxb - > cur_input ) ) ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2009-01-19 01:59:11 +03:00
mxb - > cur_freq = * f ;
DEB_EE ( ( " VIDIOC_S_FREQUENCY: freq:0x%08x. \n " , mxb - > cur_freq . frequency ) ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
/* tune in desired frequency */
2009-02-07 17:18:05 +03:00
tuner_call ( mxb , tuner , s_frequency , & mxb - > cur_freq ) ;
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
/* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */
spin_lock ( & dev - > slock ) ;
vv - > vbi_fieldcount = 0 ;
spin_unlock ( & dev - > slock ) ;
return 0 ;
}
static int vidioc_g_audio ( struct file * file , void * fh , struct v4l2_audio * a )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2009-05-02 23:38:47 +04:00
if ( a - > index > MXB_INPUTS ) {
2009-01-19 01:59:11 +03:00
DEB_D ( ( " VIDIOC_G_AUDIO %d out of range. \n " , a - > index ) ) ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " VIDIOC_G_AUDIO %d. \n " , a - > index ) ) ;
memcpy ( a , & mxb_audios [ video_audio_connect [ mxb - > cur_input ] ] , sizeof ( struct v4l2_audio ) ) ;
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_s_audio ( struct file * file , void * fh , struct v4l2_audio * a )
{
DEB_D ( ( " VIDIOC_S_AUDIO %d. \n " , a - > index ) ) ;
return 0 ;
}
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register ( struct file * file , void * fh , struct v4l2_dbg_register * reg )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
2005-04-17 02:20:36 +04:00
2009-02-07 17:18:05 +03:00
return call_all ( dev , core , g_register , reg ) ;
2009-01-19 01:59:11 +03:00
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static int vidioc_s_register ( struct file * file , void * fh , struct v4l2_dbg_register * reg )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
2005-04-17 02:20:36 +04:00
2009-02-07 17:18:05 +03:00
return call_all ( dev , core , s_register , reg ) ;
2009-01-19 01:59:11 +03:00
}
# endif
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static long vidioc_default ( struct file * file , void * fh , int cmd , void * arg )
{
struct saa7146_dev * dev = ( ( struct saa7146_fh * ) fh ) - > dev ;
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
switch ( cmd ) {
2005-04-17 02:20:36 +04:00
case MXB_S_AUDIO_CD :
{
2009-01-19 01:59:11 +03:00
int i = * ( int * ) arg ;
2006-03-17 16:37:02 +03:00
2008-09-07 00:24:30 +04:00
if ( i < 0 | | i > = MXB_AUDIOS ) {
2009-01-19 01:59:11 +03:00
DEB_D ( ( " illegal argument to MXB_S_AUDIO_CD: i:%d. \n " , i ) ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " MXB_S_AUDIO_CD: i:%d. \n " , i ) ) ;
2005-04-17 02:20:36 +04:00
2009-04-02 18:26:22 +04:00
tea6420_route_cd ( mxb , i ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
case MXB_S_AUDIO_LINE :
{
2009-01-19 01:59:11 +03:00
int i = * ( int * ) arg ;
2006-03-17 16:37:02 +03:00
2008-09-07 00:24:30 +04:00
if ( i < 0 | | i > = MXB_AUDIOS ) {
2009-01-19 01:59:11 +03:00
DEB_D ( ( " illegal argument to MXB_S_AUDIO_LINE: i:%d. \n " , i ) ) ;
2005-04-17 02:20:36 +04:00
return - EINVAL ;
}
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " MXB_S_AUDIO_LINE: i:%d. \n " , i ) ) ;
2009-04-02 18:26:22 +04:00
tea6420_route_line ( mxb , i ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-01-19 01:59:11 +03:00
default :
/*
DEB2 ( printk ( " does not handle this ioctl. \n " ) ) ;
*/
return - ENOIOCTLCMD ;
}
return 0 ;
}
2005-04-17 02:20:36 +04:00
2009-01-19 01:59:11 +03:00
static struct saa7146_ext_vv vv_data ;
/* this function only gets called when the probing was successful */
static int mxb_attach ( struct saa7146_dev * dev , struct saa7146_pci_extension_data * info )
{
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
DEB_EE ( ( " dev:%p \n " , dev ) ) ;
2006-03-17 16:37:02 +03:00
2009-01-19 01:59:11 +03:00
/* checking for i2c-devices can be omitted here, because we
already did this in " mxb_vl42_probe " */
2008-09-07 00:24:30 +04:00
2009-01-19 01:59:11 +03:00
saa7146_vv_init ( dev , & vv_data ) ;
vv_data . ops . vidioc_queryctrl = vidioc_queryctrl ;
vv_data . ops . vidioc_g_ctrl = vidioc_g_ctrl ;
vv_data . ops . vidioc_s_ctrl = vidioc_s_ctrl ;
vv_data . ops . vidioc_enum_input = vidioc_enum_input ;
vv_data . ops . vidioc_g_input = vidioc_g_input ;
vv_data . ops . vidioc_s_input = vidioc_s_input ;
vv_data . ops . vidioc_g_tuner = vidioc_g_tuner ;
vv_data . ops . vidioc_s_tuner = vidioc_s_tuner ;
vv_data . ops . vidioc_g_frequency = vidioc_g_frequency ;
vv_data . ops . vidioc_s_frequency = vidioc_s_frequency ;
vv_data . ops . vidioc_g_audio = vidioc_g_audio ;
vv_data . ops . vidioc_s_audio = vidioc_s_audio ;
2008-09-07 00:24:30 +04:00
# ifdef CONFIG_VIDEO_ADV_DEBUG
2009-01-19 01:59:11 +03:00
vv_data . ops . vidioc_g_register = vidioc_g_register ;
vv_data . ops . vidioc_s_register = vidioc_s_register ;
2008-09-07 00:24:30 +04:00
# endif
2009-01-19 01:59:11 +03:00
vv_data . ops . vidioc_default = vidioc_default ;
if ( saa7146_register_device ( & mxb - > video_dev , dev , " mxb " , VFL_TYPE_GRABBER ) ) {
ERR ( ( " cannot register capture v4l2 device. skipping. \n " ) ) ;
return - 1 ;
}
/* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/
if ( MXB_BOARD_CAN_DO_VBI ( dev ) ) {
if ( saa7146_register_device ( & mxb - > vbi_dev , dev , " mxb " , VFL_TYPE_VBI ) ) {
ERR ( ( " cannot register vbi v4l2 device. skipping. \n " ) ) ;
}
2005-04-17 02:20:36 +04:00
}
2009-01-19 01:59:11 +03:00
printk ( " mxb: found Multimedia eXtension Board #%d. \n " , mxb_num ) ;
mxb_num + + ;
mxb_init_done ( dev ) ;
return 0 ;
}
static int mxb_detach ( struct saa7146_dev * dev )
{
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
DEB_EE ( ( " dev:%p \n " , dev ) ) ;
saa7146_unregister_device ( & mxb - > video_dev , dev ) ;
if ( MXB_BOARD_CAN_DO_VBI ( dev ) )
saa7146_unregister_device ( & mxb - > vbi_dev , dev ) ;
saa7146_vv_release ( dev ) ;
mxb_num - - ;
i2c_del_adapter ( & mxb - > i2c_adapter ) ;
kfree ( mxb ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2008-09-04 00:11:54 +04:00
static int std_callback ( struct saa7146_dev * dev , struct saa7146_standard * standard )
2005-04-17 02:20:36 +04:00
{
2008-09-04 00:11:54 +04:00
struct mxb * mxb = ( struct mxb * ) dev - > ext_priv ;
2005-04-17 02:20:36 +04:00
2008-09-04 00:11:54 +04:00
if ( V4L2_STD_PAL_I = = standard - > id ) {
2006-03-14 08:20:41 +03:00
v4l2_std_id std = V4L2_STD_PAL_I ;
2008-09-04 00:11:54 +04:00
2005-04-17 02:20:36 +04:00
DEB_D ( ( " VIDIOC_S_STD: setting mxb for PAL_I. \n " ) ) ;
/* set the 7146 gpio register -- I don't know what this does exactly */
2006-03-17 16:37:02 +03:00
saa7146_write ( dev , GPIO_CTRL , 0x00404050 ) ;
2005-04-17 02:20:36 +04:00
/* unset the 7111 gpio register -- I don't know what this does exactly */
2009-02-07 17:18:05 +03:00
saa7111a_call ( mxb , core , s_gpio , 0 ) ;
2009-04-01 10:52:39 +04:00
tuner_call ( mxb , core , s_std , std ) ;
2005-04-17 02:20:36 +04:00
} else {
2006-03-14 08:20:41 +03:00
v4l2_std_id std = V4L2_STD_PAL_BG ;
2008-09-04 00:11:54 +04:00
2005-04-17 02:20:36 +04:00
DEB_D ( ( " VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM. \n " ) ) ;
/* set the 7146 gpio register -- I don't know what this does exactly */
2006-03-17 16:37:02 +03:00
saa7146_write ( dev , GPIO_CTRL , 0x00404050 ) ;
2005-04-17 02:20:36 +04:00
/* set the 7111 gpio register -- I don't know what this does exactly */
2009-02-07 17:18:05 +03:00
saa7111a_call ( mxb , core , s_gpio , 1 ) ;
2009-04-01 10:52:39 +04:00
tuner_call ( mxb , core , s_std , std ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
static struct saa7146_standard standard [ ] = {
{
. name = " PAL-BG " , . id = V4L2_STD_PAL_BG ,
. v_offset = 0x17 , . v_field = 288 ,
. h_offset = 0x14 , . h_pixels = 680 ,
. v_max_out = 576 , . h_max_out = 768 ,
} , {
. name = " PAL-I " , . id = V4L2_STD_PAL_I ,
. v_offset = 0x17 , . v_field = 288 ,
. h_offset = 0x14 , . h_pixels = 680 ,
. v_max_out = 576 , . h_max_out = 768 ,
} , {
. name = " NTSC " , . id = V4L2_STD_NTSC ,
. v_offset = 0x16 , . v_field = 240 ,
. h_offset = 0x06 , . h_pixels = 708 ,
. v_max_out = 480 , . h_max_out = 640 ,
} , {
. name = " SECAM " , . id = V4L2_STD_SECAM ,
. v_offset = 0x14 , . v_field = 288 ,
. h_offset = 0x14 , . h_pixels = 720 ,
. v_max_out = 576 , . h_max_out = 768 ,
}
} ;
static struct saa7146_pci_extension_data mxb = {
2006-03-17 16:37:02 +03:00
. ext_priv = " Multimedia eXtension Board " ,
. ext = & extension ,
2005-04-17 02:20:36 +04:00
} ;
static struct pci_device_id pci_tbl [ ] = {
{
. vendor = PCI_VENDOR_ID_PHILIPS ,
. device = PCI_DEVICE_ID_PHILIPS_SAA7146 ,
. subvendor = 0x0000 ,
. subdevice = 0x0000 ,
. driver_data = ( unsigned long ) & mxb ,
} , {
. vendor = 0 ,
}
} ;
MODULE_DEVICE_TABLE ( pci , pci_tbl ) ;
static struct saa7146_ext_vv vv_data = {
. inputs = MXB_INPUTS ,
. capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE ,
. stds = & standard [ 0 ] ,
. num_stds = sizeof ( standard ) / sizeof ( struct saa7146_standard ) ,
2006-03-17 16:37:02 +03:00
. std_callback = & std_callback ,
2005-04-17 02:20:36 +04:00
} ;
static struct saa7146_extension extension = {
. name = MXB_IDENTIFIER ,
. flags = SAA7146_USE_I2C_IRQ ,
2006-03-17 16:37:02 +03:00
2005-04-17 02:20:36 +04:00
. pci_tbl = & pci_tbl [ 0 ] ,
. module = THIS_MODULE ,
. probe = mxb_probe ,
. attach = mxb_attach ,
. detach = mxb_detach ,
. irq_mask = 0 ,
. irq_func = NULL ,
2006-03-17 16:37:02 +03:00
} ;
2005-04-17 02:20:36 +04:00
static int __init mxb_init_module ( void )
{
2008-09-07 00:24:30 +04:00
if ( saa7146_register_extension ( & extension ) ) {
2005-04-17 02:20:36 +04:00
DEB_S ( ( " failed to register extension. \n " ) ) ;
return - ENODEV ;
}
2006-03-17 16:37:02 +03:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static void __exit mxb_cleanup_module ( void )
{
saa7146_unregister_extension ( & extension ) ;
}
module_init ( mxb_init_module ) ;
module_exit ( mxb_cleanup_module ) ;
MODULE_DESCRIPTION ( " video4linux-2 driver for the Siemens-Nixdorf 'Multimedia eXtension board' " ) ;
MODULE_AUTHOR ( " Michael Hunold <michael@mihu.de> " ) ;
MODULE_LICENSE ( " GPL " ) ;