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

📄 xup_v2pro_dip.c

📁 Xilinx ISE&EDK 8.2平台的快速点餐系统设计
💻 C
字号:
/*
 File: xup_v2pro_dip.c
 Description: DIP driver for Xilinx XUP Virtex-II Pro board
 Author: 
 Date:
*/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/devfs_fs_kernel.h>
//#include <linux/spinlock.h>
#include <linux/proc_fs.h>
//#include <linux/delay.h>


#define		XUP_V2PRO_DIP_DEVICENAME		"xup_v2pro_dip"


#define  	XUP_V2PRO_DIP_REG_BASE_ADDR		0x40020000
#define  	DIP_CHANNEL1_DATA_REG			(*(volatile unsigned long *)(XUP_V2PRO_DIP_REG_BASE_ADDR+0x00))
#define		DIP_CHANNEL1_3STATE_REG			(*(volatile unsigned long *)(XUP_V2PRO_DIP_REG_BASE_ADDR+0x04))


#ifdef DIP_DUAL_CHANNEL
#define		DIP_CHANNEL2_DATA_REG			(*(volatile unsigned long *)(XUP_V2PRO_DIP_REG_BASE_ADDR+0x08))
#define		DIP_CHANNEL2_3STATE_REG			(*(volatile unsigned long *)(XUP_V2PRO_DIP_REG_BASE_ADDR+0x0C))
#endif


#define DEBUG
#ifdef  DEBUG
#define DIP_DEBUG(fmt,args...)  			printk("%s: " fmt, __FUNCTION__, ## args)
#else
#define DIP_DEBUG(fmt,args...) 
#endif


// #define  XUP_V2PRO_DIP_SET_TIMEOUT			_IOWR('L', 0x80, unsigned long)
#define  XUP_V2PRO_DIP_START_TIMER			_IOWR('L', 0x81, unsigned long)
#define  XUP_V2PRO_DIP_STOP_TIMER			_IOWR('L', 0x82, unsigned long)


#ifdef CONFIG_DEVFS_FS
static devfs_handle_t devfs_xup_v2pro_dip = NULL;
#endif


#define DIP_TIMER_INTERVALS    				1	//500		// 0.5s


// dip timer flag
#define  DIP_TIMER_FLAG_ON	0x80
#define  DIP_TIMER_FLAG_OFF	0x81


static struct timer_list   dip_timer;
static int                 dip_timer_flag = 0;
static spinlock_t	   dip_timer_lock;


static  struct proc_dir_entry * dip_proc_dir_entry = NULL;

static int xup_v2pro_dip_major;

#if 0
static void xup_v2pro_dip_set_on( int bit )
{
	volatile unsigned long data;
	
	data = DIP_CHANNEL1_3STATE_REG;
	data = data & ( ~( 1<< (bit-1) ) );
	DIP_CHANNEL1_3STATE_REG = data;
	
	DIP_DEBUG( "data=0x%x,bit=0x%x\n", data, bit );
}

static void xup_v2pro_dip_set_off( int bit )
{
	volatile unsigned long data;
	
	data = DIP_CHANNEL1_3STATE_REG;
	data = data | ( 1 << bit );
	DIP_CHANNEL1_3STATE_REG = data;
	
	DIP_DEBUG( "data=0x%x,bit=0x%x\n", data, bit );
}
#endif

static void xup_v2pro_dip_timer_routine( void * pbit )
{
	unsigned long expire;
	volatile unsigned long dip_data;
	unsigned long bit;

	DIP_DEBUG( "Entering\n" );

	expire = jiffies + (DIP_TIMER_INTERVALS) * HZ ;/// 1000;

	// read current value
	dip_data = DIP_CHANNEL1_3STATE_REG;

	bit = ( unsigned long)pbit;

	DIP_DEBUG( "1. bit=0x%x, pbit=0x%x,dip_data=0x%x\n", bit, (unsigned long)pbit, dip_data );

	if( bit == 0 ){
		dip_data = ~(dip_data & 0xf );
	}
	else{
		if( ( dip_data & ( 1 << (bit-1) ) ) == 0 ){
			DIP_DEBUG( "2. bit=0x%x, dip_data=0x%x\n", bit, dip_data );
			dip_data = dip_data | ( 1 << (bit-1) );
		}
		else{
			DIP_DEBUG( "3. bit=0x%x, dip_data=0x%x\n", bit, dip_data );
			dip_data = dip_data & ( 0xf - ( 1 << ( bit-1 ) ) );	//( 0 << (bit-1) );
		}
	}
	DIP_DEBUG( "4. after modified: dip_data=0x%x\n", dip_data );

	DIP_CHANNEL1_3STATE_REG = dip_data;

	mod_timer( &dip_timer, expire );
	
	DIP_DEBUG( "Leaving\n" );
}


static void xup_v2pro_dip_timer_init( int bit )
{
	DIP_DEBUG( "Entering\n" );

	if( bit == 0 ){
		DIP_CHANNEL1_3STATE_REG = 0xf;
	}

	init_timer(&dip_timer);
	dip_timer.function = xup_v2pro_dip_timer_routine;
	dip_timer.data  = bit;
	dip_timer.expires = jiffies + HZ * DIP_TIMER_INTERVALS; // / 1000;
	add_timer( &dip_timer );

	DIP_DEBUG( "Leaving\n" );
}


static void xup_v2pro_dip_timer_exit( void )
{
	del_timer(&dip_timer);
}


static void xup_v2pro_dip_hardware_init( void )
{
	// set all dip to turn off
	DIP_CHANNEL1_3STATE_REG = (volatile unsigned long)0x0;
}



static int xup_v2pro_dip_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	DIP_DEBUG( "Entering\n" );

	switch( cmd ){
		case XUP_V2PRO_DIP_START_TIMER:
			DIP_DEBUG( "Starting a new timer\n" );
			spin_lock( &dip_timer_lock );
	
			// if timer had already started, stop it, and restart a new timer		
			if( dip_timer_flag == DIP_TIMER_FLAG_ON ){
				xup_v2pro_dip_timer_exit( );
	//			dip_timer_flag = DIP_TIMER_FLAG_OFF;
			}				
			
			xup_v2pro_dip_timer_init( arg );
			dip_timer_flag = DIP_TIMER_FLAG_ON;
			
			spin_unlock( &dip_timer_lock );			
//			xup_v2pro_dip_timer_init(arg);
			break;
		case XUP_V2PRO_DIP_STOP_TIMER:
			DIP_DEBUG( "Stoping timer\n" );
			spin_lock( &dip_timer_lock );
			if( dip_timer_flag == DIP_TIMER_FLAG_ON ){
				xup_v2pro_dip_timer_exit( );
				dip_timer_flag = DIP_TIMER_FLAG_OFF;
			}
			spin_unlock( &dip_timer_lock );			

			break;	
	}
	
	DIP_DEBUG( "Leaving\n" );

	return 0;
}

static ssize_t xup_v2pro_dip_read(struct file *filp, char *buf, size_t count, loff_t * f_pos)
{

	buf[0] = (char) (0xf-(DIP_CHANNEL1_3STATE_REG & 0xf));
	
	DIP_DEBUG( "buffer:0x%x,0x%x\n", buf[0], buf[1] );
	DIP_DEBUG( "register value:0x%x\n", DIP_CHANNEL1_3STATE_REG );
	
	return 1;
}


static ssize_t   xup_v2pro_dip_write(struct file *filp, char *buf, size_t count, loff_t * f_pos)
{
#if 0	
	int i;

	DIP_CHANNEL1_3STATE_REG = (volatile unsigned long)(0xF);
	for( i=0; i<1000; i++ );
#endif

	spin_lock( &dip_timer_lock );
	if( dip_timer_flag == DIP_TIMER_FLAG_ON ){
		xup_v2pro_dip_timer_exit( );
		dip_timer_flag = DIP_TIMER_FLAG_OFF;
	}
	spin_unlock( &dip_timer_lock );


	DIP_CHANNEL1_3STATE_REG = (volatile unsigned long)(buf[0]);
	
	DIP_DEBUG( "buffer:0x%x, count=0x%x\n", buf[0], count );

	DIP_DEBUG( "register 3-state:0x%x, data:0x%x\n", DIP_CHANNEL1_3STATE_REG, DIP_CHANNEL1_DATA_REG );
	
	return 1;
}

static int xup_v2pro_dip_open( struct inode * inode, struct file * file )
{
	MOD_INC_USE_COUNT;

	return 0;
}


static int xup_v2pro_dip_close( struct inode * inode, struct file * file )
{
	MOD_DEC_USE_COUNT;
	
	return 0;
}



static struct file_operations xup_v2pro_dip_fops = {
			owner: THIS_MODULE,
			ioctl: xup_v2pro_dip_ioctl,
			read:  xup_v2pro_dip_read,
			write: xup_v2pro_dip_write,
			open:  xup_v2pro_dip_open,
			release: xup_v2pro_dip_close,
};


static int __init xup_v2pro_dip_init( void )
{
	xup_v2pro_dip_major = register_chrdev( 0, XUP_V2PRO_DIP_DEVICENAME, &xup_v2pro_dip_fops );
	if( xup_v2pro_dip_major < 0 ){
		printk( "register faidip!\n" );
		return -1;
	}
		
#ifdef  CONFIG_DEVFS_FS
        devfs_xup_v2pro_dip = devfs_register(NULL, XUP_V2PRO_DIP_DEVICENAME, DEVFS_FL_DEFAULT,
                               xup_v2pro_dip_major, 1, S_IFCHR | S_IRUGO | S_IWUSR,
                               &xup_v2pro_dip_fops, NULL);
#endif

	dip_proc_dir_entry = create_proc_entry( XUP_V2PRO_DIP_DEVICENAME, 0, NULL );
	if( dip_proc_dir_entry != NULL )
		dip_proc_dir_entry->proc_fops = &xup_v2pro_dip_fops;
	
	xup_v2pro_dip_hardware_init( );

	spin_lock( &dip_timer_lock );
	dip_timer_flag = DIP_TIMER_FLAG_OFF;
	spin_unlock( &dip_timer_lock );

	return 0;
}


static void __exit xup_v2pro_dip_exit( void )
{
	spin_lock( &dip_timer_lock );
	if( dip_timer_flag == DIP_TIMER_FLAG_ON ){
		xup_v2pro_dip_timer_exit( );
		dip_timer_flag = DIP_TIMER_FLAG_OFF;
	}
	spin_unlock( &dip_timer_lock );

	remove_proc_entry( XUP_V2PRO_DIP_DEVICENAME, NULL );	
#ifdef CONFIG_DEVFS_FS
	devfs_unregister(devfs_xup_v2pro_dip);
#endif

	unregister_chrdev( xup_v2pro_dip_major, XUP_V2PRO_DIP_DEVICENAME );
}

//EXPORT_NO_SYMBOLS;

/* EXPORTED FUNCTIONS */
//EXPORT_SYMBOL(xup_v2pro_dip_set_on);
//EXPORT_SYMBOL(xup_v2pro_dip_set_off);

MODULE_AUTHOR("Cactus Software Labs.");
MODULE_LICENSE("GPL");

module_init(xup_v2pro_dip_init);
module_exit(xup_v2pro_dip_exit);

⌨️ 快捷键说明

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