2005-04-17 02:20:36 +04:00
/*
* Media Vision Pro Movie Studio
* or
* " all you need is an I2C bus some RAM and a prayer "
*
* This draws heavily on code
*
* ( c ) Wolfgang Koehler , wolf @ first . gmd . de , Dec . 1994
* Kiefernring 15
* 14478 Potsdam , Germany
*
* Most of this code is directly derived from his userspace driver .
2008-10-27 21:13:47 +03:00
* His driver works so send any reports to alan @ lxorguk . ukuu . org . uk
* unless the userspace driver also doesn ' t work for you . . .
2006-03-25 15:19:53 +03:00
*
2005-04-17 02:20:36 +04:00
* Changes :
2009-11-25 18:47:02 +03:00
* 25 - 11 - 2009 Hans Verkuil < hverkuil @ xs4all . nl >
* - converted to version 2 of the V4L API .
* 08 / 07 / 2003 Daniele Bellucci < bellucda @ tiscali . it >
* - pms_capture : report back - EFAULT
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/ioport.h>
# include <linux/init.h>
2009-11-25 18:47:02 +03:00
# include <linux/version.h>
# include <linux/mutex.h>
2009-12-14 22:43:13 +03:00
# include <linux/uaccess.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
2009-11-25 18:47:02 +03:00
# include <linux/videodev2.h>
2006-06-05 17:26:32 +04:00
# include <media/v4l2-common.h>
2008-07-20 15:12:02 +04:00
# include <media/v4l2-ioctl.h>
2009-11-25 18:37:00 +03:00
# include <media/v4l2-device.h>
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
MODULE_LICENSE ( " GPL " ) ;
2005-04-17 02:20:36 +04:00
# define MOTOROLA 1
2009-11-25 18:47:02 +03:00
# define PHILIPS2 2 /* SAA7191 */
2005-04-17 02:20:36 +04:00
# define PHILIPS1 3
# define MVVMEMORYWIDTH 0x40 /* 512 bytes */
2009-11-25 18:37:00 +03:00
struct i2c_info {
2005-04-17 02:20:36 +04:00
u8 slave ;
u8 sub ;
u8 data ;
u8 hits ;
} ;
2009-11-25 18:37:00 +03:00
struct pms {
struct v4l2_device v4l2_dev ;
struct video_device vdev ;
int height ;
int width ;
2009-11-25 18:47:02 +03:00
int depth ;
int input ;
s32 brightness , saturation , hue , contrast ;
2009-11-25 18:37:00 +03:00
unsigned long in_use ;
struct mutex lock ;
int i2c_count ;
struct i2c_info i2cinfo [ 64 ] ;
int decoder ;
int standard ; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
2009-11-25 18:47:02 +03:00
v4l2_std_id std ;
2009-11-25 18:37:00 +03:00
int io ;
int data ;
void __iomem * mem ;
} ;
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
static struct pms pms_card ;
2005-04-17 02:20:36 +04:00
/*
* I / O ports and Shared Memory
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
static int io_port = 0x250 ;
module_param ( io_port , int , 0 ) ;
static int mem_base = 0xc8000 ;
module_param ( mem_base , int , 0 ) ;
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
static int video_nr = - 1 ;
module_param ( video_nr , int , 0 ) ;
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
static inline void mvv_write ( struct pms * dev , u8 index , u8 value )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
outw ( index | ( value < < 8 ) , dev - > io ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static inline u8 mvv_read ( struct pms * dev , u8 index )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
outb ( index , dev - > io ) ;
return inb ( dev - > data ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static int pms_i2c_stat ( struct pms * dev , u8 slave )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
int counter = 0 ;
2005-04-17 02:20:36 +04:00
int i ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
outb ( 0x28 , dev - > io ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
while ( ( inb ( dev - > data ) & 0x01 ) = = 0 )
if ( counter + + = = 256 )
2005-04-17 02:20:36 +04:00
break ;
2009-11-25 18:37:00 +03:00
while ( ( inb ( dev - > data ) & 0x01 ) ! = 0 )
if ( counter + + = = 256 )
2005-04-17 02:20:36 +04:00
break ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
outb ( slave , dev - > io ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
counter = 0 ;
while ( ( inb ( dev - > data ) & 0x01 ) = = 0 )
if ( counter + + = = 256 )
2005-04-17 02:20:36 +04:00
break ;
2009-11-25 18:37:00 +03:00
while ( ( inb ( dev - > data ) & 0x01 ) ! = 0 )
if ( counter + + = = 256 )
2005-04-17 02:20:36 +04:00
break ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
for ( i = 0 ; i < 12 ; i + + ) {
char st = inb ( dev - > data ) ;
if ( ( st & 2 ) ! = 0 )
2005-04-17 02:20:36 +04:00
return - 1 ;
2009-11-25 18:37:00 +03:00
if ( ( st & 1 ) = = 0 )
2005-04-17 02:20:36 +04:00
break ;
}
2009-11-25 18:37:00 +03:00
outb ( 0x29 , dev - > io ) ;
return inb ( dev - > data ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static int pms_i2c_write ( struct pms * dev , u16 slave , u16 sub , u16 data )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
int skip = 0 ;
2005-04-17 02:20:36 +04:00
int count ;
int i ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
for ( i = 0 ; i < dev - > i2c_count ; i + + ) {
if ( ( dev - > i2cinfo [ i ] . slave = = slave ) & &
( dev - > i2cinfo [ i ] . sub = = sub ) ) {
if ( dev - > i2cinfo [ i ] . data = = data )
skip = 1 ;
dev - > i2cinfo [ i ] . data = data ;
i = dev - > i2c_count + 1 ;
2005-04-17 02:20:36 +04:00
}
}
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
if ( i = = dev - > i2c_count & & dev - > i2c_count < 64 ) {
dev - > i2cinfo [ dev - > i2c_count ] . slave = slave ;
dev - > i2cinfo [ dev - > i2c_count ] . sub = sub ;
dev - > i2cinfo [ dev - > i2c_count ] . data = data ;
dev - > i2c_count + + ;
2005-04-17 02:20:36 +04:00
}
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
if ( skip )
2005-04-17 02:20:36 +04:00
return 0 ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x29 , sub ) ;
mvv_write ( dev , 0x2A , data ) ;
mvv_write ( dev , 0x28 , slave ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
outb ( 0x28 , dev - > io ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
count = 0 ;
while ( ( inb ( dev - > data ) & 1 ) = = 0 )
if ( count > 255 )
2005-04-17 02:20:36 +04:00
break ;
2009-11-25 18:37:00 +03:00
while ( ( inb ( dev - > data ) & 1 ) ! = 0 )
if ( count > 255 )
2005-04-17 02:20:36 +04:00
break ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
count = inb ( dev - > data ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
if ( count & 2 )
2005-04-17 02:20:36 +04:00
return - 1 ;
return count ;
}
2009-11-25 18:37:00 +03:00
static int pms_i2c_read ( struct pms * dev , int slave , int sub )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
int i ;
for ( i = 0 ; i < dev - > i2c_count ; i + + ) {
if ( dev - > i2cinfo [ i ] . slave = = slave & & dev - > i2cinfo [ i ] . sub = = sub )
return dev - > i2cinfo [ i ] . data ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2009-11-25 18:37:00 +03:00
static void pms_i2c_andor ( struct pms * dev , int slave , int sub , int and , int or )
2005-04-17 02:20:36 +04:00
{
2006-03-25 15:19:53 +03:00
u8 tmp ;
2009-11-25 18:37:00 +03:00
tmp = pms_i2c_read ( dev , slave , sub ) ;
tmp = ( tmp & and ) | or ;
pms_i2c_write ( dev , slave , sub , tmp ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Control functions
*/
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
static void pms_videosource ( struct pms * dev , short source )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:47:02 +03:00
switch ( dev - > decoder ) {
case MOTOROLA :
break ;
case PHILIPS2 :
pms_i2c_andor ( dev , 0x8a , 0x06 , 0x7f , source ? 0x80 : 0 ) ;
break ;
case PHILIPS1 :
break ;
}
mvv_write ( dev , 0x2E , 0x31 ) ;
/* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30);
But could not make this work correctly . Only Composite input
worked for me . */
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_hue ( struct pms * dev , short hue )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
switch ( dev - > decoder ) {
case MOTOROLA :
pms_i2c_write ( dev , 0x8a , 0x00 , hue ) ;
break ;
case PHILIPS2 :
pms_i2c_write ( dev , 0x8a , 0x07 , hue ) ;
break ;
case PHILIPS1 :
pms_i2c_write ( dev , 0x42 , 0x07 , hue ) ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2009-11-25 18:47:02 +03:00
static void pms_saturation ( struct pms * dev , short sat )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
switch ( dev - > decoder ) {
case MOTOROLA :
2009-11-25 18:47:02 +03:00
pms_i2c_write ( dev , 0x8a , 0x00 , sat ) ;
2009-11-25 18:37:00 +03:00
break ;
case PHILIPS1 :
2009-11-25 18:47:02 +03:00
pms_i2c_write ( dev , 0x42 , 0x12 , sat ) ;
2009-11-25 18:37:00 +03:00
break ;
2005-04-17 02:20:36 +04:00
}
}
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
static void pms_contrast ( struct pms * dev , short contrast )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
switch ( dev - > decoder ) {
case MOTOROLA :
pms_i2c_write ( dev , 0x8a , 0x00 , contrast ) ;
break ;
case PHILIPS1 :
pms_i2c_write ( dev , 0x42 , 0x13 , contrast ) ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2009-11-25 18:37:00 +03:00
static void pms_brightness ( struct pms * dev , short brightness )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
switch ( dev - > decoder ) {
case MOTOROLA :
pms_i2c_write ( dev , 0x8a , 0x00 , brightness ) ;
pms_i2c_write ( dev , 0x8a , 0x00 , brightness ) ;
pms_i2c_write ( dev , 0x8a , 0x00 , brightness ) ;
break ;
case PHILIPS1 :
pms_i2c_write ( dev , 0x42 , 0x19 , brightness ) ;
break ;
2005-04-17 02:20:36 +04:00
}
}
2009-11-25 18:37:00 +03:00
static void pms_format ( struct pms * dev , short format )
2005-04-17 02:20:36 +04:00
{
int target ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
dev - > standard = format ;
if ( dev - > decoder = = PHILIPS1 )
target = 0x42 ;
else if ( dev - > decoder = = PHILIPS2 )
target = 0x8a ;
2005-04-17 02:20:36 +04:00
else
return ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
switch ( format ) {
case 0 : /* Auto */
pms_i2c_andor ( dev , target , 0x0d , 0xfe , 0x00 ) ;
pms_i2c_andor ( dev , target , 0x0f , 0x3f , 0x80 ) ;
break ;
case 1 : /* NTSC */
pms_i2c_andor ( dev , target , 0x0d , 0xfe , 0x00 ) ;
pms_i2c_andor ( dev , target , 0x0f , 0x3f , 0x40 ) ;
break ;
case 2 : /* PAL */
pms_i2c_andor ( dev , target , 0x0d , 0xfe , 0x00 ) ;
pms_i2c_andor ( dev , target , 0x0f , 0x3f , 0x00 ) ;
break ;
case 3 : /* SECAM */
pms_i2c_andor ( dev , target , 0x0d , 0xfe , 0x01 ) ;
pms_i2c_andor ( dev , target , 0x0f , 0x3f , 0x00 ) ;
break ;
2005-04-17 02:20:36 +04:00
}
}
# ifdef FOR_FUTURE_EXPANSION
/*
* These features of the PMS card are not currently exposes . They
2006-03-25 15:19:53 +03:00
* could become a private v4l ioctl for PMSCONFIG or somesuch if
2005-04-17 02:20:36 +04:00
* people need it . We also don ' t yet use the PMS interrupt .
*/
2009-11-25 18:37:00 +03:00
static void pms_hstart ( struct pms * dev , short start )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
switch ( dev - > decoder ) {
case PHILIPS1 :
pms_i2c_write ( dev , 0x8a , 0x05 , start ) ;
pms_i2c_write ( dev , 0x8a , 0x18 , start ) ;
break ;
case PHILIPS2 :
pms_i2c_write ( dev , 0x42 , 0x05 , start ) ;
pms_i2c_write ( dev , 0x42 , 0x18 , start ) ;
break ;
2005-04-17 02:20:36 +04:00
}
}
/*
* Bandpass filters
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
static void pms_bandpass ( struct pms * dev , short pass )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x06 , 0xcf , ( pass & 0x03 ) < < 4 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x06 , 0xcf , ( pass & 0x03 ) < < 4 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_antisnow ( struct pms * dev , short snow )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x06 , 0xf3 , ( snow & 0x03 ) < < 2 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x06 , 0xf3 , ( snow & 0x03 ) < < 2 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_sharpness ( struct pms * dev , short sharp )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x06 , 0xfc , sharp & 0x03 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x06 , 0xfc , sharp & 0x03 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_chromaagc ( struct pms * dev , short agc )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x0c , 0x9f , ( agc & 0x03 ) < < 5 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x0c , 0x9f , ( agc & 0x03 ) < < 5 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_vertnoise ( struct pms * dev , short noise )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x10 , 0xfc , noise & 3 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x10 , 0xfc , noise & 3 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_forcecolour ( struct pms * dev , short colour )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x0c , 0x7f , ( colour & 1 ) < < 7 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x0c , 0x7 , ( colour & 1 ) < < 7 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_antigamma ( struct pms * dev , short gamma )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0xb8 , 0x00 , 0x7f , ( gamma & 1 ) < < 7 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x20 , 0x7 , ( gamma & 1 ) < < 7 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_prefilter ( struct pms * dev , short filter )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x06 , 0xbf , ( filter & 1 ) < < 6 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x06 , 0xbf , ( filter & 1 ) < < 6 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_hfilter ( struct pms * dev , short filter )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0xb8 , 0x04 , 0x1f , ( filter & 7 ) < < 5 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x24 , 0x1f , ( filter & 7 ) < < 5 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_vfilter ( struct pms * dev , short filter )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0xb8 , 0x08 , 0x9f , ( filter & 3 ) < < 5 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x28 , 0x9f , ( filter & 3 ) < < 5 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_killcolour ( struct pms * dev , short colour )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 ) {
pms_i2c_andor ( dev , 0x8a , 0x08 , 0x07 , ( colour & 0x1f ) < < 3 ) ;
pms_i2c_andor ( dev , 0x8a , 0x09 , 0x07 , ( colour & 0x1f ) < < 3 ) ;
} else if ( dev - > decoder = = PHILIPS1 ) {
pms_i2c_andor ( dev , 0x42 , 0x08 , 0x07 , ( colour & 0x1f ) < < 3 ) ;
pms_i2c_andor ( dev , 0x42 , 0x09 , 0x07 , ( colour & 0x1f ) < < 3 ) ;
2005-04-17 02:20:36 +04:00
}
}
2009-11-25 18:37:00 +03:00
static void pms_chromagain ( struct pms * dev , short chroma )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_write ( dev , 0x8a , 0x11 , chroma ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_write ( dev , 0x42 , 0x11 , chroma ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_spacialcompl ( struct pms * dev , short data )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x3b , data ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_spacialcomph ( struct pms * dev , short data )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x3a , data ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_vstart ( struct pms * dev , short start )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x16 , start ) ;
mvv_write ( dev , 0x17 , ( start > > 8 ) & 0x01 ) ;
2005-04-17 02:20:36 +04:00
}
# endif
2009-11-25 18:37:00 +03:00
static void pms_secamcross ( struct pms * dev , short cross )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x0f , 0xdf , ( cross & 1 ) < < 5 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x0f , 0xdf , ( cross & 1 ) < < 5 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_swsense ( struct pms * dev , short sense )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 ) {
pms_i2c_write ( dev , 0x8a , 0x0a , sense ) ;
pms_i2c_write ( dev , 0x8a , 0x0b , sense ) ;
} else if ( dev - > decoder = = PHILIPS1 ) {
pms_i2c_write ( dev , 0x42 , 0x0a , sense ) ;
pms_i2c_write ( dev , 0x42 , 0x0b , sense ) ;
2005-04-17 02:20:36 +04:00
}
}
2009-11-25 18:37:00 +03:00
static void pms_framerate ( struct pms * dev , short frr )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:47:02 +03:00
int fps = ( dev - > std & V4L2_STD_525_60 ) ? 30 : 25 ;
2009-11-25 18:37:00 +03:00
if ( frr = = 0 )
2005-04-17 02:20:36 +04:00
return ;
2009-11-25 18:37:00 +03:00
fps = fps / frr ;
mvv_write ( dev , 0x14 , 0x80 | fps ) ;
mvv_write ( dev , 0x15 , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_vert ( struct pms * dev , u8 deciden , u8 decinum )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x1c , deciden ) ; /* Denominator */
mvv_write ( dev , 0x1d , decinum ) ; /* Numerator */
2005-04-17 02:20:36 +04:00
}
/*
* Turn 16 bit ratios into best small ratio the chipset can grok
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
static void pms_vertdeci ( struct pms * dev , unsigned short decinum , unsigned short deciden )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
/* Knock it down by / 5 once */
if ( decinum % 5 = = 0 ) {
deciden / = 5 ;
decinum / = 5 ;
2005-04-17 02:20:36 +04:00
}
/*
* 3 ' s
*/
2009-11-25 18:37:00 +03:00
while ( decinum % 3 = = 0 & & deciden % 3 = = 0 ) {
deciden / = 3 ;
decinum / = 3 ;
2005-04-17 02:20:36 +04:00
}
/*
* 2 ' s
*/
2009-11-25 18:37:00 +03:00
while ( decinum % 2 = = 0 & & deciden % 2 = = 0 ) {
decinum / = 2 ;
deciden / = 2 ;
2005-04-17 02:20:36 +04:00
}
/*
* Fudgyify
*/
2009-11-25 18:37:00 +03:00
while ( deciden > 32 ) {
deciden / = 2 ;
decinum = ( decinum + 1 ) / 2 ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
if ( deciden = = 32 )
2005-04-17 02:20:36 +04:00
deciden - - ;
2009-11-25 18:37:00 +03:00
pms_vert ( dev , deciden , decinum ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_horzdeci ( struct pms * dev , short decinum , short deciden )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( decinum < = 512 ) {
if ( decinum % 5 = = 0 ) {
decinum / = 5 ;
deciden / = 5 ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
} else {
decinum = 512 ;
deciden = 640 ; /* 768 would be ideal */
2005-04-17 02:20:36 +04:00
}
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
while ( ( ( decinum | deciden ) & 1 ) = = 0 ) {
decinum > > = 1 ;
deciden > > = 1 ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
while ( deciden > 32 ) {
deciden > > = 1 ;
decinum = ( decinum + 1 ) > > 1 ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
if ( deciden = = 32 )
2005-04-17 02:20:36 +04:00
deciden - - ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x24 , 0x80 | deciden ) ;
mvv_write ( dev , 0x25 , decinum ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void pms_resolution ( struct pms * dev , short width , short height )
2005-04-17 02:20:36 +04:00
{
int fg_height ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
fg_height = height ;
if ( fg_height > 280 )
fg_height = 280 ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x18 , fg_height ) ;
mvv_write ( dev , 0x19 , fg_height > > 8 ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:47:02 +03:00
if ( dev - > std & V4L2_STD_525_60 ) {
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x1a , 0xfc ) ;
mvv_write ( dev , 0x1b , 0x00 ) ;
if ( height > fg_height )
pms_vertdeci ( dev , 240 , 240 ) ;
2005-04-17 02:20:36 +04:00
else
2009-11-25 18:37:00 +03:00
pms_vertdeci ( dev , fg_height , 240 ) ;
} else {
mvv_write ( dev , 0x1a , 0x1a ) ;
mvv_write ( dev , 0x1b , 0x01 ) ;
if ( fg_height > 256 )
pms_vertdeci ( dev , 270 , 270 ) ;
2005-04-17 02:20:36 +04:00
else
2009-11-25 18:37:00 +03:00
pms_vertdeci ( dev , fg_height , 270 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x12 , 0 ) ;
mvv_write ( dev , 0x13 , MVVMEMORYWIDTH ) ;
mvv_write ( dev , 0x42 , 0x00 ) ;
mvv_write ( dev , 0x43 , 0x00 ) ;
mvv_write ( dev , 0x44 , MVVMEMORYWIDTH ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x22 , width + 8 ) ;
mvv_write ( dev , 0x23 , ( width + 8 ) > > 8 ) ;
2005-04-17 02:20:36 +04:00
2009-11-25 18:47:02 +03:00
if ( dev - > std & V4L2_STD_525_60 )
2009-11-25 18:37:00 +03:00
pms_horzdeci ( dev , width , 640 ) ;
2005-04-17 02:20:36 +04:00
else
2009-11-25 18:37:00 +03:00
pms_horzdeci ( dev , width + 8 , 768 ) ;
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x30 , mvv_read ( dev , 0x30 ) & 0xfe ) ;
mvv_write ( dev , 0x08 , mvv_read ( dev , 0x08 ) | 0x01 ) ;
mvv_write ( dev , 0x01 , mvv_read ( dev , 0x01 ) & 0xfd ) ;
mvv_write ( dev , 0x32 , 0x00 ) ;
mvv_write ( dev , 0x33 , MVVMEMORYWIDTH ) ;
2005-04-17 02:20:36 +04:00
}
/*
* Set Input
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
static void pms_vcrinput ( struct pms * dev , short input )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
if ( dev - > decoder = = PHILIPS2 )
pms_i2c_andor ( dev , 0x8a , 0x0d , 0x7f , ( input & 1 ) < < 7 ) ;
else if ( dev - > decoder = = PHILIPS1 )
pms_i2c_andor ( dev , 0x42 , 0x0d , 0x7f , ( input & 1 ) < < 7 ) ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static int pms_capture ( struct pms * dev , char __user * buf , int rgb555 , int count )
2005-04-17 02:20:36 +04:00
{
int y ;
2009-11-25 18:37:00 +03:00
int dw = 2 * dev - > width ;
char tmp [ dw + 32 ] ; /* using a temp buffer is faster than direct */
2005-04-17 02:20:36 +04:00
int cnt = 0 ;
2009-11-25 18:37:00 +03:00
int len = 0 ;
2005-04-17 02:20:36 +04:00
unsigned char r8 = 0x5 ; /* value for reg8 */
if ( rgb555 )
r8 | = 0x20 ; /* else use untranslated rgb = 565 */
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x08 , r8 ) ; /* capture rgb555/565, init DRAM, PC enable */
2005-04-17 02:20:36 +04:00
/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
for ( y = 0 ; y < dev - > height ; y + + ) {
writeb ( 0 , dev - > mem ) ; /* synchronisiert neue Zeile */
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/*
* This is in truth a fifo , be very careful as if you
* forgot this odd things will occur 8 )
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
memcpy_fromio ( tmp , dev - > mem , dw + 32 ) ; /* discard 16 word */
2005-04-17 02:20:36 +04:00
cnt - = dev - > height ;
2009-11-25 18:37:00 +03:00
while ( cnt < = 0 ) {
2005-04-17 02:20:36 +04:00
/*
* Don ' t copy too far
*/
2009-11-25 18:37:00 +03:00
int dt = dw ;
if ( dt + len > count )
dt = count - len ;
2005-04-17 02:20:36 +04:00
cnt + = dev - > height ;
2009-11-25 18:37:00 +03:00
if ( copy_to_user ( buf , tmp + 32 , dt ) )
2005-04-17 02:20:36 +04:00
return len ? len : - EFAULT ;
2006-03-25 15:19:53 +03:00
buf + = dt ;
2005-04-17 02:20:36 +04:00
len + = dt ;
}
}
return len ;
}
/*
* Video4linux interfacing
*/
2009-11-25 18:47:02 +03:00
static int pms_querycap ( struct file * file , void * priv ,
struct v4l2_capability * vcap )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
struct pms * dev = video_drvdata ( file ) ;
2009-11-25 18:47:02 +03:00
strlcpy ( vcap - > driver , dev - > v4l2_dev . name , sizeof ( vcap - > driver ) ) ;
strlcpy ( vcap - > card , " Mediavision PMS " , sizeof ( vcap - > card ) ) ;
strlcpy ( vcap - > bus_info , " ISA " , sizeof ( vcap - > bus_info ) ) ;
vcap - > version = KERNEL_VERSION ( 0 , 0 , 3 ) ;
vcap - > capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE ;
return 0 ;
}
2009-11-25 18:37:00 +03:00
2009-11-25 18:47:02 +03:00
static int pms_enum_input ( struct file * file , void * fh , struct v4l2_input * vin )
{
static const char * inputs [ 4 ] = {
" Composite " ,
" S-Video " ,
" Composite (VCR) " ,
" S-Video (VCR) "
} ;
2009-11-25 18:37:00 +03:00
2009-11-25 18:47:02 +03:00
if ( vin - > index > 3 )
return - EINVAL ;
strlcpy ( vin - > name , inputs [ vin - > index ] , sizeof ( vin - > name ) ) ;
vin - > type = V4L2_INPUT_TYPE_CAMERA ;
vin - > audioset = 0 ;
vin - > tuner = 0 ;
vin - > std = V4L2_STD_ALL ;
vin - > status = 0 ;
return 0 ;
}
2009-11-25 18:37:00 +03:00
2009-11-25 18:47:02 +03:00
static int pms_g_input ( struct file * file , void * fh , unsigned int * inp )
{
struct pms * dev = video_drvdata ( file ) ;
2009-11-25 18:37:00 +03:00
2009-11-25 18:47:02 +03:00
* inp = dev - > input ;
return 0 ;
}
static int pms_s_input ( struct file * file , void * fh , unsigned int inp )
{
struct pms * dev = video_drvdata ( file ) ;
if ( inp > 3 )
return - EINVAL ;
mutex_lock ( & dev - > lock ) ;
dev - > input = inp ;
pms_videosource ( dev , inp & 1 ) ;
pms_vcrinput ( dev , inp > > 1 ) ;
mutex_unlock ( & dev - > lock ) ;
return 0 ;
}
static int pms_g_std ( struct file * file , void * fh , v4l2_std_id * std )
{
struct pms * dev = video_drvdata ( file ) ;
* std = dev - > std ;
return 0 ;
}
static int pms_s_std ( struct file * file , void * fh , v4l2_std_id * std )
{
struct pms * dev = video_drvdata ( file ) ;
int ret = 0 ;
dev - > std = * std ;
mutex_lock ( & dev - > lock ) ;
if ( dev - > std & V4L2_STD_NTSC ) {
pms_framerate ( dev , 30 ) ;
pms_secamcross ( dev , 0 ) ;
pms_format ( dev , 1 ) ;
} else if ( dev - > std & V4L2_STD_PAL ) {
pms_framerate ( dev , 25 ) ;
pms_secamcross ( dev , 0 ) ;
pms_format ( dev , 2 ) ;
} else if ( dev - > std & V4L2_STD_SECAM ) {
pms_framerate ( dev , 25 ) ;
pms_secamcross ( dev , 1 ) ;
pms_format ( dev , 2 ) ;
} else {
ret = - EINVAL ;
2009-11-25 18:37:00 +03:00
}
2009-11-25 18:47:02 +03:00
/*
switch ( v - > mode ) {
case VIDEO_MODE_AUTO :
pms_framerate ( dev , 25 ) ;
pms_secamcross ( dev , 0 ) ;
pms_format ( dev , 0 ) ;
break ;
} */
mutex_unlock ( & dev - > lock ) ;
return 0 ;
}
static int pms_queryctrl ( struct file * file , void * priv ,
struct v4l2_queryctrl * qc )
{
switch ( qc - > id ) {
case V4L2_CID_BRIGHTNESS :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 139 ) ;
case V4L2_CID_CONTRAST :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 70 ) ;
case V4L2_CID_SATURATION :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 64 ) ;
case V4L2_CID_HUE :
return v4l2_ctrl_query_fill ( qc , 0 , 255 , 1 , 0 ) ;
2009-11-25 18:37:00 +03:00
}
2009-11-25 18:47:02 +03:00
return - EINVAL ;
}
2009-11-25 18:37:00 +03:00
2009-11-25 18:47:02 +03:00
static int pms_g_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
{
struct pms * dev = video_drvdata ( file ) ;
int ret = 0 ;
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
ctrl - > value = dev - > brightness ;
break ;
case V4L2_CID_CONTRAST :
ctrl - > value = dev - > contrast ;
break ;
case V4L2_CID_SATURATION :
ctrl - > value = dev - > saturation ;
break ;
case V4L2_CID_HUE :
ctrl - > value = dev - > hue ;
break ;
default :
ret = - EINVAL ;
break ;
2009-11-25 18:37:00 +03:00
}
2009-11-25 18:47:02 +03:00
return ret ;
}
static int pms_s_ctrl ( struct file * file , void * priv ,
struct v4l2_control * ctrl )
{
struct pms * dev = video_drvdata ( file ) ;
int ret = 0 ;
mutex_lock ( & dev - > lock ) ;
switch ( ctrl - > id ) {
case V4L2_CID_BRIGHTNESS :
dev - > brightness = ctrl - > value ;
pms_brightness ( dev , dev - > brightness ) ;
break ;
case V4L2_CID_CONTRAST :
dev - > contrast = ctrl - > value ;
pms_contrast ( dev , dev - > contrast ) ;
break ;
case V4L2_CID_SATURATION :
dev - > saturation = ctrl - > value ;
pms_saturation ( dev , dev - > saturation ) ;
break ;
case V4L2_CID_HUE :
dev - > hue = ctrl - > value ;
pms_hue ( dev , dev - > hue ) ;
break ;
2009-11-25 18:37:00 +03:00
default :
2009-11-25 18:47:02 +03:00
ret = - EINVAL ;
break ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:47:02 +03:00
mutex_unlock ( & dev - > lock ) ;
return ret ;
}
static int pms_g_fmt_vid_cap ( struct file * file , void * fh , struct v4l2_format * fmt )
{
struct pms * dev = video_drvdata ( file ) ;
struct v4l2_pix_format * pix = & fmt - > fmt . pix ;
pix - > width = dev - > width ;
pix - > height = dev - > height ;
pix - > pixelformat = dev - > width = = 15 ?
V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565 ;
pix - > field = V4L2_FIELD_NONE ;
pix - > bytesperline = 2 * dev - > width ;
pix - > sizeimage = 2 * dev - > width * dev - > height ;
/* Just a guess */
pix - > colorspace = V4L2_COLORSPACE_SRGB ;
return 0 ;
}
static int pms_try_fmt_vid_cap ( struct file * file , void * fh , struct v4l2_format * fmt )
{
struct v4l2_pix_format * pix = & fmt - > fmt . pix ;
if ( pix - > height < 16 | | pix - > height > 480 )
return - EINVAL ;
if ( pix - > width < 16 | | pix - > width > 640 )
return - EINVAL ;
if ( pix - > pixelformat ! = V4L2_PIX_FMT_RGB555 & &
pix - > pixelformat ! = V4L2_PIX_FMT_RGB565 )
return - EINVAL ;
pix - > field = V4L2_FIELD_NONE ;
pix - > bytesperline = 2 * pix - > width ;
pix - > sizeimage = 2 * pix - > width * pix - > height ;
/* Just a guess */
pix - > colorspace = V4L2_COLORSPACE_SRGB ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2009-11-25 18:47:02 +03:00
static int pms_s_fmt_vid_cap ( struct file * file , void * fh , struct v4l2_format * fmt )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:47:02 +03:00
struct pms * dev = video_drvdata ( file ) ;
struct v4l2_pix_format * pix = & fmt - > fmt . pix ;
int ret = pms_try_fmt_vid_cap ( file , fh , fmt ) ;
if ( ret )
return ret ;
mutex_lock ( & dev - > lock ) ;
dev - > width = pix - > width ;
dev - > height = pix - > height ;
dev - > depth = ( pix - > pixelformat = = V4L2_PIX_FMT_RGB555 ) ? 15 : 16 ;
pms_resolution ( dev , dev - > width , dev - > height ) ;
/* Ok we figured out what to use from our wide choice */
mutex_unlock ( & dev - > lock ) ;
return 0 ;
}
static int pms_enum_fmt_vid_cap ( struct file * file , void * fh , struct v4l2_fmtdesc * fmt )
{
static struct v4l2_fmtdesc formats [ ] = {
{ 0 , 0 , 0 ,
" RGB 5:5:5 " , V4L2_PIX_FMT_RGB555 ,
{ 0 , 0 , 0 , 0 }
} ,
{ 0 , 0 , 0 ,
" RGB 5:6:5 " , V4L2_PIX_FMT_RGB565 ,
{ 0 , 0 , 0 , 0 }
} ,
} ;
enum v4l2_buf_type type = fmt - > type ;
if ( fmt - > index > 1 )
return - EINVAL ;
* fmt = formats [ fmt - > index ] ;
fmt - > type = type ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
static ssize_t pms_read ( struct file * file , char __user * buf ,
size_t count , loff_t * ppos )
{
2009-11-25 18:37:00 +03:00
struct pms * dev = video_drvdata ( file ) ;
2005-04-17 02:20:36 +04:00
int len ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
mutex_lock ( & dev - > lock ) ;
2009-11-25 18:47:02 +03:00
len = pms_capture ( dev , buf , ( dev - > depth = = 15 ) , count ) ;
2009-11-25 18:37:00 +03:00
mutex_unlock ( & dev - > lock ) ;
2005-04-17 02:20:36 +04:00
return len ;
}
2008-12-30 12:58:20 +03:00
static int pms_exclusive_open ( struct file * file )
2008-08-23 12:31:47 +04:00
{
2009-11-25 18:37:00 +03:00
struct pms * dev = video_drvdata ( file ) ;
2008-08-23 12:31:47 +04:00
2009-11-25 18:37:00 +03:00
return test_and_set_bit ( 0 , & dev - > in_use ) ? - EBUSY : 0 ;
2008-08-23 12:31:47 +04:00
}
2008-12-30 12:58:20 +03:00
static int pms_exclusive_release ( struct file * file )
2008-08-23 12:31:47 +04:00
{
2009-11-25 18:37:00 +03:00
struct pms * dev = video_drvdata ( file ) ;
2008-08-23 12:31:47 +04:00
2009-11-25 18:37:00 +03:00
clear_bit ( 0 , & dev - > in_use ) ;
2008-08-23 12:31:47 +04:00
return 0 ;
}
2008-12-30 12:58:20 +03:00
static const struct v4l2_file_operations pms_fops = {
2005-04-17 02:20:36 +04:00
. owner = THIS_MODULE ,
2008-08-23 12:31:47 +04:00
. open = pms_exclusive_open ,
. release = pms_exclusive_release ,
2009-11-25 18:47:02 +03:00
. ioctl = video_ioctl2 ,
2005-04-17 02:20:36 +04:00
. read = pms_read ,
} ;
2009-11-25 18:47:02 +03:00
static const struct v4l2_ioctl_ops pms_ioctl_ops = {
. vidioc_querycap = pms_querycap ,
. vidioc_g_input = pms_g_input ,
. vidioc_s_input = pms_s_input ,
. vidioc_enum_input = pms_enum_input ,
. vidioc_g_std = pms_g_std ,
. vidioc_s_std = pms_s_std ,
. vidioc_queryctrl = pms_queryctrl ,
. vidioc_g_ctrl = pms_g_ctrl ,
. vidioc_s_ctrl = pms_s_ctrl ,
. vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap ,
. vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap ,
. vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap ,
. vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap ,
} ;
2005-04-17 02:20:36 +04:00
/*
* Probe for and initialise the Mediavision PMS
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
static int init_mediavision ( struct pms * dev )
2005-04-17 02:20:36 +04:00
{
int id ;
int idec , decst ;
int i ;
2009-11-25 18:37:00 +03:00
static const unsigned char i2c_defs [ ] = {
0x4c , 0x30 , 0x00 , 0xe8 ,
0xb6 , 0xe2 , 0x00 , 0x00 ,
0xff , 0xff , 0x00 , 0x00 ,
0x00 , 0x00 , 0x78 , 0x98 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x34 , 0x0a , 0xf4 , 0xce ,
0xe4
2005-04-17 02:20:36 +04:00
} ;
2009-11-25 18:37:00 +03:00
dev - > mem = ioremap ( mem_base , 0x800 ) ;
if ( ! dev - > mem )
2005-04-17 02:20:36 +04:00
return - ENOMEM ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
if ( ! request_region ( 0x9a01 , 1 , " Mediavision PMS config " ) ) {
printk ( KERN_WARNING " mediavision: unable to detect: 0x9a01 in use. \n " ) ;
iounmap ( dev - > mem ) ;
2005-04-17 02:20:36 +04:00
return - EBUSY ;
}
2009-11-25 18:37:00 +03:00
if ( ! request_region ( dev - > io , 3 , " Mediavision PMS " ) ) {
printk ( KERN_WARNING " mediavision: I/O port %d in use. \n " , dev - > io ) ;
release_region ( 0x9a01 , 1 ) ;
iounmap ( dev - > mem ) ;
2005-04-17 02:20:36 +04:00
return - EBUSY ;
}
2009-11-25 18:37:00 +03:00
outb ( 0xb8 , 0x9a01 ) ; /* Unlock */
outb ( dev - > io > > 4 , 0x9a01 ) ; /* Set IO port */
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
id = mvv_read ( dev , 3 ) ;
decst = pms_i2c_stat ( dev , 0x43 ) ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
if ( decst ! = - 1 )
idec = 2 ;
else if ( pms_i2c_stat ( dev , 0xb9 ) ! = - 1 )
idec = 3 ;
else if ( pms_i2c_stat ( dev , 0x8b ) ! = - 1 )
idec = 1 ;
2006-03-25 15:19:53 +03:00
else
2009-11-25 18:37:00 +03:00
idec = 0 ;
2005-04-17 02:20:36 +04:00
printk ( KERN_INFO " PMS type is %d \n " , idec ) ;
2009-11-25 18:37:00 +03:00
if ( idec = = 0 ) {
release_region ( dev - > io , 3 ) ;
release_region ( 0x9a01 , 1 ) ;
iounmap ( dev - > mem ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
/*
* Ok we have a PMS of some sort
*/
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
mvv_write ( dev , 0x04 , mem_base > > 12 ) ; /* Set the memory area */
2006-03-25 15:19:53 +03:00
2005-04-17 02:20:36 +04:00
/* Ok now load the defaults */
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
for ( i = 0 ; i < 0x19 ; i + + ) {
if ( i2c_defs [ i ] = = 0xff )
pms_i2c_andor ( dev , 0x8a , i , 0x07 , 0x00 ) ;
2005-04-17 02:20:36 +04:00
else
2009-11-25 18:37:00 +03:00
pms_i2c_write ( dev , 0x8a , i , i2c_defs [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
pms_i2c_write ( dev , 0xb8 , 0x00 , 0x12 ) ;
pms_i2c_write ( dev , 0xb8 , 0x04 , 0x00 ) ;
pms_i2c_write ( dev , 0xb8 , 0x07 , 0x00 ) ;
pms_i2c_write ( dev , 0xb8 , 0x08 , 0x00 ) ;
pms_i2c_write ( dev , 0xb8 , 0x09 , 0xff ) ;
pms_i2c_write ( dev , 0xb8 , 0x0a , 0x00 ) ;
pms_i2c_write ( dev , 0xb8 , 0x0b , 0x10 ) ;
pms_i2c_write ( dev , 0xb8 , 0x10 , 0x03 ) ;
mvv_write ( dev , 0x01 , 0x00 ) ;
mvv_write ( dev , 0x05 , 0xa0 ) ;
mvv_write ( dev , 0x08 , 0x25 ) ;
mvv_write ( dev , 0x09 , 0x00 ) ;
mvv_write ( dev , 0x0a , 0x20 | MVVMEMORYWIDTH ) ;
mvv_write ( dev , 0x10 , 0x02 ) ;
mvv_write ( dev , 0x1e , 0x0c ) ;
mvv_write ( dev , 0x1f , 0x03 ) ;
mvv_write ( dev , 0x26 , 0x06 ) ;
mvv_write ( dev , 0x2b , 0x00 ) ;
mvv_write ( dev , 0x2c , 0x20 ) ;
mvv_write ( dev , 0x2d , 0x00 ) ;
mvv_write ( dev , 0x2f , 0x70 ) ;
mvv_write ( dev , 0x32 , 0x00 ) ;
mvv_write ( dev , 0x33 , MVVMEMORYWIDTH ) ;
mvv_write ( dev , 0x34 , 0x00 ) ;
mvv_write ( dev , 0x35 , 0x00 ) ;
mvv_write ( dev , 0x3a , 0x80 ) ;
mvv_write ( dev , 0x3b , 0x10 ) ;
mvv_write ( dev , 0x20 , 0x00 ) ;
mvv_write ( dev , 0x21 , 0x00 ) ;
mvv_write ( dev , 0x30 , 0x22 ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
/*
* Initialization and module stuff
*/
2006-03-25 15:19:53 +03:00
2008-09-03 23:48:21 +04:00
# ifndef MODULE
static int enable ;
module_param ( enable , int , 0 ) ;
# endif
2009-11-25 18:37:00 +03:00
static int __init pms_init ( void )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
struct pms * dev = & pms_card ;
struct v4l2_device * v4l2_dev = & dev - > v4l2_dev ;
int res ;
strlcpy ( v4l2_dev - > name , " pms " , sizeof ( v4l2_dev - > name ) ) ;
v4l2_info ( v4l2_dev , " Mediavision Pro Movie Studio driver 0.03 \n " ) ;
2006-03-25 15:19:53 +03:00
2008-09-03 23:48:21 +04:00
# ifndef MODULE
if ( ! enable ) {
2009-11-25 18:37:00 +03:00
v4l2_err ( v4l2_dev ,
" PMS: not enabled, use pms.enable=1 to probe \n " ) ;
2008-09-03 23:48:21 +04:00
return - ENODEV ;
}
# endif
2009-11-25 18:37:00 +03:00
dev - > decoder = PHILIPS2 ;
dev - > io = io_port ;
dev - > data = io_port + 1 ;
2006-03-25 15:19:53 +03:00
2009-11-25 18:37:00 +03:00
if ( init_mediavision ( dev ) ) {
v4l2_err ( v4l2_dev , " Board not found. \n " ) ;
2005-04-17 02:20:36 +04:00
return - ENODEV ;
}
2009-11-25 18:37:00 +03:00
res = v4l2_device_register ( NULL , v4l2_dev ) ;
if ( res < 0 ) {
v4l2_err ( v4l2_dev , " Could not register v4l2_device \n " ) ;
return res ;
}
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
strlcpy ( dev - > vdev . name , v4l2_dev - > name , sizeof ( dev - > vdev . name ) ) ;
dev - > vdev . v4l2_dev = v4l2_dev ;
dev - > vdev . fops = & pms_fops ;
2009-11-25 18:47:02 +03:00
dev - > vdev . ioctl_ops = & pms_ioctl_ops ;
2009-11-25 18:37:00 +03:00
dev - > vdev . release = video_device_release_empty ;
video_set_drvdata ( & dev - > vdev , dev ) ;
mutex_init ( & dev - > lock ) ;
2009-11-25 18:47:02 +03:00
dev - > std = V4L2_STD_NTSC_M ;
2009-11-25 18:37:00 +03:00
dev - > height = 240 ;
dev - > width = 320 ;
2009-11-25 18:47:02 +03:00
dev - > depth = 15 ;
dev - > brightness = 139 ;
dev - > contrast = 70 ;
dev - > hue = 0 ;
dev - > saturation = 64 ;
2009-11-25 18:37:00 +03:00
pms_swsense ( dev , 75 ) ;
pms_resolution ( dev , 320 , 240 ) ;
pms_videosource ( dev , 0 ) ;
pms_vcrinput ( dev , 0 ) ;
if ( video_register_device ( & dev - > vdev , VFL_TYPE_GRABBER , video_nr ) < 0 ) {
v4l2_device_unregister ( & dev - > v4l2_dev ) ;
release_region ( dev - > io , 3 ) ;
release_region ( 0x9a01 , 1 ) ;
iounmap ( dev - > mem ) ;
return - EINVAL ;
}
return 0 ;
2005-04-17 02:20:36 +04:00
}
2009-11-25 18:37:00 +03:00
static void __exit pms_exit ( void )
2005-04-17 02:20:36 +04:00
{
2009-11-25 18:37:00 +03:00
struct pms * dev = & pms_card ;
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
video_unregister_device ( & dev - > vdev ) ;
release_region ( dev - > io , 3 ) ;
release_region ( 0x9a01 , 1 ) ;
iounmap ( dev - > mem ) ;
}
2005-04-17 02:20:36 +04:00
2009-11-25 18:37:00 +03:00
module_init ( pms_init ) ;
module_exit ( pms_exit ) ;