/*
* 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.
* His driver works so send any reports to alan@redhat.com unless the
* userspace driver also doesn't work for you...
*
* Changes:
* 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
* - pms_capture: report back -EFAULT
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#define MOTOROLA 1
#define PHILIPS2 2
#define PHILIPS1 3
#define MVVMEMORYWIDTH 0x40 /* 512 bytes */
struct pms_device
{
struct video_device v;
struct video_picture picture;
int height;
int width;
struct mutex lock;
};
struct i2c_info
{
u8 slave;
u8 sub;
u8 data;
u8 hits;
};
static int i2c_count = 0;
static struct i2c_info i2cinfo[64];
static int decoder = PHILIPS2;
static int standard = 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
/*
* I/O ports and Shared Memory
*/
static int io_port = 0x250;
static int data_port = 0x251;
static int mem_base = 0xC8000;
static void __iomem *mem;
static int video_nr = -1;
static inline void mvv_write(u8 index, u8 value)
{
outw(index|(value<<8), io_port);
}
static inline u8 mvv_read(u8 index)
{
outb(index, io_port);
return inb(data_port);
}
static int pms_i2c_stat(u8 slave)
{
int counter;
int i;
outb(0x28, io_port);
counter=0;
while((inb(data_port)&0x01)==0)
if(counter++==256)
break;
while((inb(data_port)&0x01)!=0)
if(counter++==256)
break;
outb(slave, io_port);
counter=0;
while((inb(data_port)&0x01)==0)
if(counter++==256)
break;
while((inb(data_port)&0x01)!=0)
if(counter++==256)
break;
for(i=0;i<12;i++)
{
char st=inb(data_port);
if((st&2)!=0)
return -1;
if((st&1)==0)
break;
}
outb(0x29, io_port);
return inb(data_port);
}
static int pms_i2c_write(u16 slave, u16 sub, u16 data)
{
int skip=0;
int count;
int i;
for(i=0;i<i2c_count;i++)
{
if((i2cinfo[i].slave==slave) &&
(i2cinfo[i].sub == sub))
{
if(i2cinfo[i].data==data)
skip=1;
i2cinfo[i].data=data;
i=i2c_count+1;
}
}
if(i==i2c_count && i2c_count<64)
{
i2cinfo[i2c_count].slave=slave;
i2cinfo[i2c_count].sub=sub;
i2cinfo[i2c_count].data=data;
i2c_count++;
}
if(skip)
return 0;
mvv_write(0x29, sub);
mvv_write(0x2A, data);
mvv_write(0x28, slave);
outb(0x28, io_port);
count=0;
while((inb(data_port)&1)==0)
if(count>255)
break;
while((inb(data_port)&1)!=0)
if(count>255)
break;
count=inb(data_port);