⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tw2834.c

📁 TW2834 的Linux驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * tw2834 - Techwell TW2834 video decoder driver version 0.0.1
 *
 * Copyright (c)  2006 Guangzhou Jinpeng Group Co., Ltd. 
 * All rights reserved.
 * David Huang<huangym@gzjp.cn>

 * This source code and any compilation or derivative thereof is the proprietary
 * information of Guangzhou Jinpeng Group and is confidential in nature. Under no
 * circumstances is this software to be exposed to or placed under an Open Source
 * License of any type without the express written permission of Guangzhou 
 * Jinpeng Group.
 */
/*
Rev Date        Author      Comments
--------------------------------------------------------------------------------
 1   20061023  huangym   Original;
 2   20061206  huangym   Add TW2834 cascade mode ;
                                      change 1x00 to cascade mode;
                                      add tw2834_set_xpath_position;
                                      change the device name;
 3   2007.03.05 wangdy    in tw2834_config.h;0x1e=0xff--->0x1e=0x7f,This is frame size CIF for Y path;
 4   2007.03.09 wangdy    0x70 from 0xc0 to 0x40,for Y path no popup,this is for 2834 cscade,only this can record work well!
 5   2007.04.08 wangdy    Delete setting PREVIEW interface after setting one position;
 6   2007.04.11 wangdy    add tw2834_ioctl_sem to avoid two threads infaluting each other,
			   			or, when split ,some channels will not PREVIEW ;
 7   2007.04.25 wangdy    0x14-0x17,0x20 regs; V blank:0x09,0x49,0x89,0xd9->0x07;
 8   2007.06.06 wangdy    command copy data from user : copy_from_user(buf,(unsigned int *)arg,16);
 						It can solve the data error when transites from user space! some channels have no video problem no more!
 9   2007.07.07 wangdy    shutdown DAC output of tw2834;
 10 2007.07.25 wangdy	  add ntsc_mode;midify ntsc color phase for video;
 11 2007.09.03 wangdy   modify get video status;
 12 2007.11.28 wangdy   modify 1x7d,1x84 for ntsc recode;
--------------------------------------------------------------------------------
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/miscdevice.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/types.h>

#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#include "tw2834.h"
#include "tw2834_config.h"

#define I2C_NAME(x) (x)->name
#define DEVNAME "tw2834"

MODULE_DESCRIPTION("Techwell TW2834 video decoder driver");
MODULE_AUTHOR("David Huang");
MODULE_LICENSE("GPL");
static int debug =2;
static int chip_number=-1;
unsigned int height;

/* Which is the address of I2C slaover.Please modify it for your necessary! */
#define master0_addr            0x84
#define slaver1_addr             0x86
#define slaver2_addr             0x88
#define slaver3_addr             0x8a

static struct semaphore tw2834_ioctl_sem;	/*2007.4.11 add to avoid two threads infaluting each other*/

	 
static char *mode_option = "pal";			/* default mode_option is pal;*/
module_param(mode_option,charp,0);

module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");

#define dprintk(num, format, args...) \
    do\
    { \
        if (debug >= num) \
            printk(format, ##args); \
    } while (0)
/* ----------------------------------------------------------------------- */

int tw2834_major =   TW2834_MAJOR;
int tw2834_minor =   0;
int tw2834_nr_devs = TW2834_NR_DEVS;   /* number of bare tw2834 devices */


struct tw2834_dev *tw2834_devices;        /* allocated in tw2834_init_module */
static struct class_simple *tw2834_class; 
static struct i2c_client *tw2834_client;
struct tw2834 {
    int norm;
};


static inline int  tw2834_chip_config(void);
static inline void set_standard(struct i2c_client * client);
static inline void tw2834_only_master_chip(void);
static inline void tw2834_tow_chip(void);
static inline void tw2834_three_chip(void);
static inline void tw2834_four_chip(void);
static inline void tw2834_all_channel_disable(struct i2c_client * client); //
static void tw2834_set_xpath_position_table(struct i2c_client * client,int ch_no,unsigned int split_num,unsigned int to_position);

int tw2834_trim(struct tw2834_dev *dev);
static inline int tw2834_read (struct i2c_client *client, u8 vi_page,u8 reg);
static ssize_t tw2834_fileread(struct file *file, char __user *buf, size_t count, loff_t *pos);
static int tw2834_open(struct inode *inode, struct file *file);
static int tw2834_command ( struct inode  *inode, struct file   *file,
                              unsigned int   cmd,   unsigned long  arg);

static struct file_operations   tw2834_fops    =   {
    .owner          =   THIS_MODULE,
    .read           =   tw2834_fileread,
    .open           =   tw2834_open,
    .release        =   NULL,
    .ioctl          =   tw2834_command,
};

#define REG_ADDR(x) (((x) << 1) + 1)
#define LOu8(x) ((unsigned char)((x) & 0xff))
#define HIu8(x) ((unsigned char)(((x) >> 8) & 0xff))
#define LOWORD(x) ((unsigned short int)((x) & 0xffff))
#define HIWORD(x) ((unsigned short int)(((x) >> 16) & 0xffff))
#define BUFFER_LENGTH (10)


/* ----------------------------------------------------------------------- */
static ssize_t tw2834_fileread(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
    ssize_t retval = 0;
    if (*pos == 0)
    {
	char kernBuf[10] = {0,0,0,0,0,0,0,0,0,0};

	if (count > BUFFER_LENGTH)
	{
		count = BUFFER_LENGTH;
	}

	if ( copy_to_user(buf, kernBuf, count) )
	{
		printk(KERN_WARNING "%s: Unable to copy_to_user all data during read.\n", __FILE__);
		retval = -EFAULT;
	}
	else
	{
		*pos += count;
		retval = count;
	}
    }

    return retval;
}
/* ----------------------------------------------------------------------- */

static  int 
tw2834_open(struct inode *inode, struct file *file)
{ 
     int num;
     struct tw2834_dev *dev;      /* device information */
     dev = container_of(inode->i_cdev, struct tw2834_dev, cdev);   

     //dprintk(1, KERN_DEBUG "major is %d,minor is %d!\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev));
     num = MINOR(inode->i_rdev);
	 
     file->private_data = dev;   /* for other methods */
     //dprintk(1, KERN_DEBUG "This is chip[%d] addr is:(0x%02x)\n",num,dev->addr << 1);

     /* now trim to 0 the length of the device if open was write-only */
     if ( (file->f_flags & O_ACCMODE) == O_WRONLY) {
         if (down_interruptible(&dev->sem))   return -ERESTARTSYS;
         tw2834_trim(dev);       /* ignore errors */
         up(&dev->sem);
     }
      return 0;                   /* success */
}



static inline int
tw2834_write (struct i2c_client *client,
           u8                 vi_page,
           u8                 reg,
           u8                 value)
{

    struct i2c_msg msg;
    u8       data[3];
    msg.addr = client->addr;
    msg.flags = 0;

    data[0] = vi_page&0x03; 
    data[1] = reg;
    data[2] = value;

    msg.buf = (char *) data;
    msg.len = 3;

    return i2c_transfer(client->adapter, &msg, 1);
}



static inline int
tw2834_write_block (struct i2c_client *client,
             u8                    vi_page,
             u8                    reg,
             const u8          *value,
             unsigned int       len)
{
    struct i2c_msg msg;
    u8                    data[32];
    unsigned int      copylen;
    int        ret = -1;

    msg.addr = client->addr;
    msg.flags = 0;
    msg.buf = (char *)data;

    data[0] = vi_page&0x03;                                                /* The first byte is register's page */

    while(len)
    {
        data[1] = reg;                                                     /* The second byte is register's address */

        if (len <=30)
        {
            copylen = len;
            len = 0;

        }
        else
        {
            copylen = 30;
            len -=30;
        }

        memcpy(&data[2], value, copylen);                               /* Copy  register's value */
        value += copylen;
        reg +=copylen;  
        msg.len = copylen + 2;

       /* the tw2834 has an autoincrement function */
       if ((ret = i2c_transfer(client->adapter, &msg, 1)) < 0)   /* Transfer a  block */  
            break;
    }

    return ret;
}

 

static inline int tw2834_read (struct i2c_client *client, 
            u8            vi_page,
            u8            reg)
{
    struct i2c_msg msg;
    u8       data[2];
    u8       rcvdata;

    msg.addr = client->addr;
    msg.flags = 0;

    data[0] = vi_page&0x03; 
    data[1] = reg;

    msg.buf = (char *) data;
    msg.len = 2;

    if( i2c_transfer(client->adapter, &msg, 1) < 0)
        return -1;
    if(i2c_master_recv(client, (char*)&rcvdata, 1)<0)
        return -1;

    return rcvdata;
}



#define HORIZON      	720
#define PAL_V        	576
#define NTSC_V      	480

/*
* founction:position and split screen on tv
* 	    ch_no, which channel
*	    split_num,split screen num:1,4,9,16
*	    to_position:on tv position is :0--(split_num-1)
*/
static void tw2834_set_xpath_position_table(struct i2c_client * client, 
				      int ch_no, 
				      unsigned int split_num,
				      unsigned int to_position)
{
	struct tw2834 *decoder;
	unsigned int    subaddr;
	unsigned int    hscale=0;
	unsigned int    vscale=0;
	unsigned int    position;
	unsigned char h_left=0;
	unsigned char h_right=0;
	unsigned char v_top=0;
	unsigned char v_bottom=0;
	unsigned char ntsc_mode=0;
	
	if(ch_no < 0 || ch_no >4)					/* error channel number */
		return;

	decoder = i2c_get_clientdata(client);


	if(decoder->norm == PAL_STD)
	{
		position =(to_position)*4;				/* for pal */
		ntsc_mode=0;
	}
	else
	{	
		position =(split_num+ to_position)*4;	/* for ntsc  */
		ntsc_mode=1;
	}
		
	{
		if(split_num == 1 )
		{
		 	hscale =  hscale1[ntsc_mode];
		 	vscale =  vscale1[ntsc_mode];
			h_left  =  preview_position_1[position++];
			h_right = preview_position_1[position++];
			v_top =   preview_position_1[position++];
			v_bottom = preview_position_1[position];
	
		}
		if(split_num == 4 )
		{
			hscale =  hscale4[ntsc_mode];
			vscale =  vscale4[ntsc_mode];
			h_left  =  preview_position_4[position++];
			h_right = preview_position_4[position++];
			v_top =   preview_position_4[position++];
			v_bottom = preview_position_4[position];
		}
		if(split_num == 9 )
		{
			hscale =  hscale9[ntsc_mode];
			vscale =  vscale9[ntsc_mode];
			h_left  =  preview_position_9[position++];
			h_right = preview_position_9[position++];
			v_top =   preview_position_9[position++];
			v_bottom = preview_position_9[position];
		}
		if(split_num == 16 )
		{
			hscale =  hscale16[ntsc_mode];
			vscale =  vscale16[ntsc_mode];
			h_left  =  preview_position_16[position++];
			h_right = preview_position_16[position++];
			v_top =   preview_position_16[position++];
			v_bottom = preview_position_16[position];
		}
	}

        //dprintk(1, KERN_DEBUG "ch_no = %d, hscale = 0x%x,  vscale = 0x%x.\n ", ch_no, hscale, vscale);

	if(decoder->norm == PAL_STD)
	{
		tw2834_write(client, 1, 0x88, 0x20);
	}
	else
	{
		tw2834_write(client, 1, 0x88, 0x19);			/* left position of tw2834 */
	}

	subaddr = 0x1c+ch_no*0x40;
	tw2834_write(client, 0, subaddr++, HIu8(hscale)); 	/* HSCALE_X[15:8] */
	tw2834_write(client, 0, subaddr, LOu8(hscale));		 /* HSCALE_X[7:0] */


	subaddr = 0x18+ch_no*0x40;
	tw2834_write(client, 0, subaddr++, HIu8(vscale));	 /* VSCALE_X[15:8] */
	tw2834_write(client, 0, subaddr, LOu8(vscale));  		 /* VSCALE_X[7:0] */

	
	subaddr = 0x30+ch_no*4;							/* position  */
	tw2834_write(client, 1, subaddr++, h_left);
	tw2834_write(client, 1, subaddr++, h_right);
	tw2834_write(client, 1, subaddr++, v_top);
	tw2834_write(client, 1, subaddr,   v_bottom);
		
	
	if(split_num == 1 )
	{	
		
		subaddr = 0x03+ch_no*0x40;					/* position and blank boundary  */
		tw2834_write(client, 0, subaddr, 0x44);
		tw2834_write(client, 0, subaddr+0x06, 0x11);
		
		subaddr = 0x14+ch_no*0x40;					/* related regs:display path and record path */
		tw2834_write(client, 0, subaddr++, 0x34);
		tw2834_write(client, 0, subaddr++, 0x00);
		tw2834_write(client, 0, subaddr++, 0x00);
		tw2834_write(client, 0, subaddr,   0x10);
		
		if(decoder->norm == PAL_STD)
		{
			subaddr = 0x20+ch_no*0x40;
			tw2834_write(client, 0, subaddr,   0x0f);
		}
		else
		{
			subaddr = 0x20+ch_no*0x40;				/* only Display path and 0x21 is record path */
			tw2834_write(client, 0, subaddr,   0x07);		
		}
		//printk("split num is 1,set fullscreen\n");		
	}
		
		
	if(split_num == 4 )
	{	
		
		if(decoder->norm == PAL_STD)
		{
			subaddr = 0x03+ch_no*0x40;				/*  position and blank boundary  */
			tw2834_write(client, 0, subaddr, 0x30);
			tw2834_write(client, 0, subaddr+0x06, 0x07);
		
			subaddr = 0x14+ch_no*0x40;				/* related regs  */
			tw2834_write(client, 0, subaddr++, 0x50);
			tw2834_write(client, 0, subaddr++, 0x30);
			tw2834_write(client, 0, subaddr++, 0xc0);
			tw2834_write(client, 0, subaddr,   0xc0);
			subaddr = 0x20+ch_no*0x40;
			tw2834_write(client, 0, subaddr,   0x0f);
		}
		else
		{
			subaddr = 0x03+ch_no*0x40;				/*  position and blank boundary  */
			tw2834_write(client, 0, subaddr, 0x30);
			tw2834_write(client, 0, subaddr+0x06, 0x10);
		
			subaddr = 0x14+ch_no*0x40;				/* related regs  */
			tw2834_write(client, 0, subaddr++, 0x00);
			tw2834_write(client, 0, subaddr++, 0x23);
			tw2834_write(client, 0, subaddr++, 0x00);
			tw2834_write(client, 0, subaddr,   0x10);
			subaddr = 0x20+ch_no*0x40;
			tw2834_write(client, 0, subaddr,   0x0f);		
		}	
		//printk("split num is %d\n",split_num);	
	}	
	
		
	if(split_num == 9 )

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -